1#include <xrpld/app/ledger/LedgerMaster.h>
2#include <xrpld/app/main/Application.h>
3#include <xrpld/app/misc/DeliverMax.h>
4#include <xrpld/app/misc/Transaction.h>
5#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
6#include <xrpld/rpc/Context.h>
7#include <xrpld/rpc/DeliveredAmount.h>
8#include <xrpld/rpc/MPTokenIssuanceID.h>
9#include <xrpld/rpc/Role.h>
10#include <xrpld/rpc/Status.h>
11#include <xrpld/rpc/detail/RPCHelpers.h>
12#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
13#include <xrpld/rpc/detail/Tuning.h>
15#include <xrpl/basics/Log.h>
16#include <xrpl/basics/base_uint.h>
17#include <xrpl/basics/chrono.h>
18#include <xrpl/basics/strHex.h>
19#include <xrpl/beast/utility/instrumentation.h>
20#include <xrpl/json/json_value.h>
21#include <xrpl/ledger/ReadView.h>
22#include <xrpl/protocol/AccountID.h>
23#include <xrpl/protocol/ErrorCodes.h>
24#include <xrpl/protocol/LedgerShortcut.h>
25#include <xrpl/protocol/NFTSyntheticSerializer.h>
26#include <xrpl/protocol/RPCErr.h>
27#include <xrpl/protocol/RippleLedgerHash.h>
28#include <xrpl/protocol/jss.h>
29#include <xrpl/rdb/RelationalDatabase.h>
30#include <xrpl/resource/Fees.h>
42static std::expected<DelegateFilter, json::Value>
48 if (!delegateNode.
isMember(jss::delegate_filter) ||
49 !delegateNode[jss::delegate_filter].
isString())
52 auto const& delegateFilterStr = delegateNode[jss::delegate_filter].
asString();
54 auto typeResult = [&] -> std::expected<DelegateType, json::Value> {
55 if (delegateFilterStr ==
"actor")
58 if (delegateFilterStr ==
"authorizer")
70 if (delegateNode.
isMember(jss::counter_party))
72 if (!delegateNode[jss::counter_party].isString())
100 if ((params.
isMember(jss::ledger_index_min) || params.
isMember(jss::ledger_index_max)) &&
104 status.inject(response);
108 if (params.
isMember(jss::ledger_index_min) || params.
isMember(jss::ledger_index_max))
111 params.
isMember(jss::ledger_index_min) && params[jss::ledger_index_min].
asInt() >= 0
112 ? params[jss::ledger_index_min].
asUInt()
115 params.
isMember(jss::ledger_index_max) && params[jss::ledger_index_max].
asInt() >= 0
116 ? params[jss::ledger_index_max].
asUInt()
121 if (params.
isMember(jss::ledger_hash))
123 auto& hashValue = params[jss::ledger_hash];
124 if (!hashValue.isString())
127 status.inject(response);
132 if (!hash.
parseHex(hashValue.asString()))
135 status.inject(response);
140 if (params.
isMember(jss::ledger_index))
143 if (params[jss::ledger_index].isNumeric())
145 ledger = params[jss::ledger_index].
asUInt();
151 if (ledgerStr ==
"current" || ledgerStr.
empty())
155 else if (ledgerStr ==
"closed")
159 else if (ledgerStr ==
"validated")
166 status.inject(response);
205 if ((ls.max > uValidatedMax && ls.max != -1) ||
206 (ls.min < uValidatedMin && ls.min != 0))
211 if (ls.min > uValidatedMin)
215 if (ls.max < uValidatedMax)
219 if (uLedgerMax < uLedgerMin)
229 auto status = getLedger(ledgerView, ls, context);
237 if (!validated || ledgerView->header().seq > uValidatedMax ||
238 ledgerView->header().seq < uValidatedMin)
242 uLedgerMin = uLedgerMax = ledgerView->header().seq;
251 return LedgerRange{.min = uLedgerMin, .max = uLedgerMax};
265 return {result, *stat};
268 result.
ledgerRange = std::get<LedgerRange>(lgrRange);
286 auto [tx, marker] = db.oldestAccountTxPageB(options);
292 auto [tx, marker] = db.newestAccountTxPageB(options);
301 auto [tx, marker] = db.oldestAccountTxPage(options);
307 auto [tx, marker] = db.newestAccountTxPage(options);
314 JLOG(context.
j.
debug()) << __func__ <<
" : finished";
334 response[jss::validated] =
true;
335 response[jss::limit] = result.
limit;
344 XRPL_ASSERT(!args.
binary,
"xrpl::populateJsonResponse : binary is not set");
346 for (
auto const& [txn, txnMeta] : *txnsData)
351 jvObj[jss::validated] =
true;
353 auto const jsonTx = (context.
apiVersion > 1 ? jss::tx_json : jss::tx);
356 jvObj[jsonTx] = txn->getJson(
362 jvObj[jss::hash] =
to_string(txn->getID());
363 jvObj[jss::ledger_index] = txn->getLedger();
364 jvObj[jss::ledger_hash] =
369 jvObj[jss::close_time_iso] =
toStringIso(*closeTime);
376 auto const& sttx = txn->getSTransaction();
381 insertDeliveredAmount(jvObj[jss::meta], context, txn, *txnMeta);
389 "xrpl::populateJsonResponse : missing "
390 "transaction metadata");
398 XRPL_ASSERT(args.
binary,
"xrpl::populateJsonResponse : binary is set");
400 for (
auto const& binaryData : std::get<TxnsDataBinary>(result.
transactions))
404 jvObj[jss::tx_blob] =
strHex(std::get<0>(binaryData));
405 auto const jsonMeta = (context.
apiVersion > 1 ? jss::meta_blob : jss::meta);
406 jvObj[jsonMeta] =
strHex(std::get<1>(binaryData));
407 jvObj[jss::ledger_index] = std::get<2>(binaryData);
408 jvObj[jss::validated] =
true;
415 response[jss::marker][jss::ledger] = result.
marker->ledgerSeq;
416 response[jss::marker][jss::seq] = result.
marker->txnSeq;
419 response[jss::marker][jss::delegate] =
true;
423 JLOG(context.
j.
debug()) << __func__ <<
" : finished";
453 auto& params = context.
params;
461 if (context.
apiVersion > 1u && params.isMember(jss::binary) && !params[jss::binary].isBool())
465 if (context.
apiVersion > 1u && params.isMember(jss::forward) && !params[jss::forward].isBool())
473 args.
binary = params.isMember(jss::binary) && params[jss::binary].asBool();
474 args.
forward = params.isMember(jss::forward) && params[jss::forward].asBool();
476 if (!params.isMember(jss::account))
479 if (!params[jss::account].isString())
494 args.
ledger = std::get<std::optional<LedgerSpecifier>>(parseRes);
496 if (params.isMember(jss::marker))
498 auto& token = params[jss::marker];
499 if (!token.isMember(jss::ledger) || !token.isMember(jss::seq) ||
505 "invalid marker. Provide ledger index via ledger field, and "
506 "transaction sequence number via seq field"};
507 status.inject(response);
511 .ledgerSeq = token[jss::ledger].asUInt(), .txnSeq = token[jss::seq].asUInt()};
514 if (params.isMember(jss::delegate))
522 return filter.error();
532 bool const markerFromDelegate = params[jss::marker].isMember(jss::delegate) &&
533 params[jss::marker][jss::delegate].isBool() &&
534 params[jss::marker][jss::delegate].asBool();
535 if (markerFromDelegate != args.
delegate.has_value())
539 "Do not mix delegate and non-delegate pagination markers in account_tx; "
540 "repeat the same `delegate` object when using a delegate marker."};
541 status.inject(response);
547 JLOG(context.
j.
debug()) << __func__ <<
" populating response";
Value & append(Value const &value)
Append value to array at the end.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
virtual Config & config()=0
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
bool getValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
uint256 getHashBySeq(std::uint32_t index)
Get a ledger's hash by sequence number using the cache.
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
bool isValidated(ReadView const &ledger)
std::vector< AccountTx > AccountTxs
std::vector< txnMetaLedgerType > MetaTxsList
std::variant< LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash > LedgerSpecifier
std::tuple< Blob, Blob, std::uint32_t > txnMetaLedgerType
virtual RelationalDatabase & getRelationalDatabase()=0
@ UInt
unsigned integer value
@ Array
array value (ordered list)
@ Object
object value (collection of name/value pairs).
Charge const kFeeMediumBurdenRpc
static constexpr LimitRange kAccountTx
Limits for the account_tx command.
void insertMPTokenIssuanceID(json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
void insertDeliverMax(json::Value &txJson, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
void insertNFTSyntheticInJson(json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
json::Value invalidFieldError(std::string const &name)
std::optional< json::Value > readLimitField(unsigned int &limit, tuning::LimitRange const &range, JsonContext const &context)
Retrieves the limit value from a JsonContext or sets a default.
json::Value missingFieldError(std::string const &name)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
RelationalDatabase::AccountTxs TxnsData
json::Value doAccountTx(rpc::JsonContext &context)
RelationalDatabase::AccountTxResult AccountTxResult
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string strHex(FwdIt begin, FwdIt end)
std::pair< AccountTxResult, rpc::Status > doAccountTxHelp(rpc::Context &context, AccountTxArgs const &args)
static std::expected< DelegateFilter, json::Value > parseDelegateFilter(json::Value const &delegateNode)
RelationalDatabase::MetaTxsList TxnsDataBinary
RelationalDatabase::txnMetaLedgerType TxnDataBinary
@ Closed
The most recently closed ledger (may not be validated).
@ Current
The current working ledger (open, not yet closed).
@ Validated
The most recently validated ledger.
std::string to_string(BaseUInt< Bits, Tag > const &a)
std::string toStringIso(date::sys_time< Duration > tp)
DelegateType
Enumeration of possible delegate types that can occur during filtering in account_tx.
@ Authorizer
This account signed and submitted transactions on behalf of another account (this account is the sign...
@ Actor
Another account signed and submitted transactions on behalf of this account (this account is the owne...
json::Value rpcError(ErrorCodeI iError)
json::Value populateJsonResponse(std::pair< AccountTxResult, rpc::Status > const &res, AccountTxArgs const &args, rpc::JsonContext const &context)
RelationalDatabase::AccountTxArgs AccountTxArgs
RelationalDatabase::LedgerSpecifier LedgerSpecifier
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
std::variant< LedgerRange, rpc::Status > getLedgerRange(rpc::Context &context, std::optional< LedgerSpecifier > const &ledgerSpecifier)
std::variant< std::optional< LedgerSpecifier >, json::Value > parseLedgerArgs(rpc::Context &context, json::Value const ¶ms)
unsigned int underlying_t
std::optional< AccountTxMarker > marker
std::optional< LedgerSpecifier > ledger
std::optional< DelegateFilter > delegate
std::variant< AccountTxs, MetaTxsList > transactions
std::optional< AccountTxMarker > marker
The context of information needed to call an RPC.
resource::Charge & loadType
LedgerMaster & ledgerMaster
Status represents the results of an operation that might fail.
void inject(json::Value &object) const
Apply the Status to a JsonObject.
ErrorCodeI toErrorCode() const
Returns the Status as an error_code_i.
static constexpr Code kOK