20 #include <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/main/Application.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/backend/PostgresDatabase.h>
26 #include <ripple/app/rdb/backend/SQLiteDatabase.h>
27 #include <ripple/core/Pg.h>
28 #include <ripple/json/json_reader.h>
29 #include <ripple/json/json_value.h>
30 #include <ripple/ledger/ReadView.h>
31 #include <ripple/net/RPCErr.h>
32 #include <ripple/protocol/ErrorCodes.h>
33 #include <ripple/protocol/NFTSyntheticSerializer.h>
34 #include <ripple/protocol/UintTypes.h>
35 #include <ripple/protocol/jss.h>
36 #include <ripple/resource/Fees.h>
37 #include <ripple/rpc/Context.h>
38 #include <ripple/rpc/DeliveredAmount.h>
39 #include <ripple/rpc/Role.h>
41 #include <grpcpp/grpcpp.h>
63 if ((params.
isMember(jss::ledger_index_min) ||
64 params.
isMember(jss::ledger_index_max)) &&
65 (params.
isMember(jss::ledger_hash) ||
69 status.inject(response);
73 if (params.
isMember(jss::ledger_index_min) ||
74 params.
isMember(jss::ledger_index_max))
76 uint32_t min = params.
isMember(jss::ledger_index_min) &&
77 params[jss::ledger_index_min].
asInt() >= 0
78 ? params[jss::ledger_index_min].
asUInt()
80 uint32_t max = params.
isMember(jss::ledger_index_max) &&
81 params[jss::ledger_index_max].
asInt() >= 0
82 ? params[jss::ledger_index_max].
asUInt()
87 else if (params.
isMember(jss::ledger_hash))
89 auto& hashValue = params[jss::ledger_hash];
90 if (!hashValue.isString())
93 status.inject(response);
98 if (!hash.
parseHex(hashValue.asString()))
101 status.inject(response);
106 else if (params.
isMember(jss::ledger_index))
109 if (params[jss::ledger_index].isNumeric())
110 ledger = params[jss::ledger_index].
asUInt();
115 if (ledgerStr ==
"current" || ledgerStr.
empty())
116 ledger = LedgerShortcut::CURRENT;
117 else if (ledgerStr ==
"closed")
118 ledger = LedgerShortcut::CLOSED;
119 else if (ledgerStr ==
"validated")
120 ledger = LedgerShortcut::VALIDATED;
125 status.inject(response);
160 if constexpr (std::is_same_v<T, LedgerRange>)
167 if ((ls.max > uValidatedMax && ls.max != -1) ||
168 (ls.min < uValidatedMin && ls.min != 0))
173 if (ls.min > uValidatedMin)
177 if (ls.max < uValidatedMax)
181 if (uLedgerMax < uLedgerMin)
191 auto const status = getLedger(ledgerView, ls, context);
200 if (!validated || ledgerView->
info().
seq > uValidatedMax ||
201 ledgerView->
info().
seq < uValidatedMin)
205 uLedgerMin = uLedgerMax = ledgerView->
info().
seq;
227 Throw<std::runtime_error>(
"Failed to get relational database");
229 return db->getAccountTx(args);
235 if (
auto stat = std::get_if<RPC::Status>(&lgrRange))
238 return {result, *stat};
241 result.
ledgerRange = std::get<LedgerRange>(lgrRange);
257 Throw<std::runtime_error>(
"Failed to get relational database");
263 auto [tx, marker] = db->oldestAccountTxPageB(options);
269 auto [tx, marker] = db->newestAccountTxPageB(options);
278 auto [tx, marker] = db->oldestAccountTxPage(options);
284 auto [tx, marker] = db->newestAccountTxPage(options);
291 JLOG(context.
j.
debug()) << __func__ <<
" : finished";
306 error.inject(response);
311 response[jss::validated] =
true;
312 response[jss::limit] = result.
limit;
319 if (
auto txnsData = std::get_if<TxnsData>(&result.
transactions))
323 for (
auto const& [txn, txnMeta] : *txnsData)
328 jvObj[jss::validated] =
true;
331 (context.
apiVersion > 1 ? jss::tx_json : jss::tx);
334 jvObj[json_tx] = txn->getJson(
338 jvObj[jss::hash] =
to_string(txn->getID());
339 jvObj[jss::ledger_index] = txn->getLedger();
340 jvObj[jss::ledger_hash] =
347 jvObj[jss::close_time_iso] =
354 auto const& sttx = txn->getSTransaction();
356 jvObj[json_tx], sttx->getTxnType(), context.
apiVersion);
361 insertDeliveredAmount(
362 jvObj[jss::meta], context, txn, *txnMeta);
366 assert(
false &&
"Missing transaction medatata");
374 for (
auto const& binaryData :
379 jvObj[jss::tx_blob] =
strHex(std::get<0>(binaryData));
380 auto const json_meta =
381 (context.
apiVersion > 1 ? jss::meta_blob : jss::meta);
382 jvObj[json_meta] =
strHex(std::get<1>(binaryData));
383 jvObj[jss::ledger_index] = std::get<2>(binaryData);
384 jvObj[jss::validated] =
true;
391 response[jss::marker][jss::ledger] = result.
marker->ledgerSeq;
392 response[jss::marker][jss::seq] = result.
marker->txnSeq;
395 response[
"used_postgres"] =
true;
398 JLOG(context.
j.
debug()) << __func__ <<
" : finished";
418 auto& params = context.
params;
426 if (context.
apiVersion > 1u && params.isMember(jss::binary) &&
427 !params[jss::binary].isBool())
431 if (context.
apiVersion > 1u && params.isMember(jss::forward) &&
432 !params[jss::forward].isBool())
437 args.
limit = params.isMember(jss::limit) ? params[jss::limit].asUInt() : 0;
438 args.
binary = params.isMember(jss::binary) && params[jss::binary].asBool();
440 params.isMember(jss::forward) && params[jss::forward].asBool();
442 if (!params.isMember(jss::account))
446 parseBase58<AccountID>(params[jss::account].asString());
453 if (
auto jv = std::get_if<Json::Value>(&parseRes))
459 args.
ledger = std::get<std::optional<LedgerSpecifier>>(parseRes);
462 if (params.isMember(jss::marker))
464 auto& token = params[jss::marker];
465 if (!token.isMember(jss::ledger) || !token.isMember(jss::seq) ||
466 !token[jss::ledger].isConvertibleTo(Json::ValueType::uintValue) ||
467 !token[jss::seq].isConvertibleTo(Json::ValueType::uintValue))
471 "invalid marker. Provide ledger index via ledger field, and "
472 "transaction sequence number via seq field"};
473 status.inject(response);
476 args.
marker = {token[jss::ledger].asUInt(), token[jss::seq].asUInt()};
480 JLOG(context.
j.
debug()) << __func__ <<
" populating response";