mirror of
https://github.com/XRPLF/clio.git
synced 2026-08-22 21:20:52 +00:00
857 lines
24 KiB
C++
857 lines
24 KiB
C++
/** @file */
|
||
#pragma once
|
||
|
||
/*
|
||
* This file contains a variety of utility functions used when executing the handlers.
|
||
*/
|
||
|
||
#include "data/AmendmentCenterInterface.hpp"
|
||
#include "data/BackendInterface.hpp"
|
||
#include "data/Types.hpp"
|
||
#include "rpc/Errors.hpp"
|
||
#include "rpc/JS.hpp"
|
||
#include "rpc/common/Types.hpp"
|
||
#include "util/JsonUtils.hpp"
|
||
#include "util/Taggable.hpp"
|
||
#include "util/log/Logger.hpp"
|
||
#include "web/Context.hpp"
|
||
|
||
#include <boost/asio/spawn.hpp>
|
||
#include <boost/json/array.hpp>
|
||
#include <boost/json/object.hpp>
|
||
#include <boost/json/value.hpp>
|
||
#include <boost/regex.hpp>
|
||
#include <boost/regex/v5/regex_match.hpp>
|
||
#include <fmt/format.h>
|
||
#include <xrpl/basics/Number.h>
|
||
#include <xrpl/basics/base_uint.h>
|
||
#include <xrpl/json/json_value.h>
|
||
#include <xrpl/protocol/AccountID.h>
|
||
#include <xrpl/protocol/Book.h>
|
||
#include <xrpl/protocol/Fees.h>
|
||
#include <xrpl/protocol/Indexes.h>
|
||
#include <xrpl/protocol/Issue.h>
|
||
#include <xrpl/protocol/Keylet.h>
|
||
#include <xrpl/protocol/LedgerFormats.h>
|
||
#include <xrpl/protocol/LedgerHeader.h>
|
||
#include <xrpl/protocol/MPTIssue.h>
|
||
#include <xrpl/protocol/PublicKey.h>
|
||
#include <xrpl/protocol/Rate.h>
|
||
#include <xrpl/protocol/SField.h>
|
||
#include <xrpl/protocol/STAmount.h>
|
||
#include <xrpl/protocol/STBase.h>
|
||
#include <xrpl/protocol/STLedgerEntry.h>
|
||
#include <xrpl/protocol/STObject.h>
|
||
#include <xrpl/protocol/STTx.h>
|
||
#include <xrpl/protocol/SecretKey.h>
|
||
#include <xrpl/protocol/Seed.h>
|
||
#include <xrpl/protocol/Serializer.h>
|
||
#include <xrpl/protocol/TxMeta.h>
|
||
#include <xrpl/protocol/UintTypes.h>
|
||
#include <xrpl/protocol/XRPAmount.h>
|
||
#include <xrpl/protocol/jss.h>
|
||
|
||
#include <chrono>
|
||
#include <cstddef>
|
||
#include <cstdint>
|
||
#include <functional>
|
||
#include <memory>
|
||
#include <optional>
|
||
#include <string>
|
||
#include <tuple>
|
||
#include <utility>
|
||
#include <vector>
|
||
|
||
namespace rpc {
|
||
|
||
/**
|
||
* @brief Enum for NFT json manipulation
|
||
*/
|
||
enum class NFTokenjson { ENABLE, DISABLE };
|
||
|
||
/**
|
||
* @brief Get a xrpl::AccountID from its string representation
|
||
*
|
||
* @param account The string representation of the account
|
||
* @return The account ID or std::nullopt if the string is not a valid account
|
||
*/
|
||
std::optional<xrpl::AccountID>
|
||
accountFromStringStrict(std::string const& account);
|
||
|
||
/**
|
||
* @brief Check whether the SLE is owned by the account
|
||
*
|
||
* @param sle The ledger entry
|
||
* @param accountID The account ID
|
||
* @return true if the SLE is owned by the account
|
||
*/
|
||
bool
|
||
isOwnedByAccount(xrpl::SLE const& sle, xrpl::AccountID const& accountID);
|
||
|
||
/**
|
||
* @brief Get the start hint for the account
|
||
*
|
||
* @param sle The ledger entry
|
||
* @param accountID The account ID
|
||
* @return The start hint
|
||
*/
|
||
std::uint64_t
|
||
getStartHint(xrpl::SLE const& sle, xrpl::AccountID const& accountID);
|
||
|
||
/**
|
||
* @brief Parse the account cursor from the JSON
|
||
*
|
||
* @param jsonCursor The JSON cursor
|
||
* @return The parsed account cursor
|
||
*/
|
||
std::optional<AccountCursor>
|
||
parseAccountCursor(std::optional<std::string> jsonCursor);
|
||
|
||
// TODO this function should probably be in a different file and namespace
|
||
/**
|
||
* @brief Deserialize a TransactionAndMetadata into a pair of STTx and STObject
|
||
*
|
||
* @param blobs The TransactionAndMetadata to deserialize
|
||
* @return The deserialized objects
|
||
*/
|
||
std::pair<std::shared_ptr<xrpl::STTx const>, std::shared_ptr<xrpl::STObject const>>
|
||
deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs);
|
||
|
||
// TODO this function should probably be in a different file and namespace
|
||
/**
|
||
* @brief Deserialize a TransactionAndMetadata into a pair of STTx and TxMeta
|
||
*
|
||
* @param blobs The TransactionAndMetadata to deserialize
|
||
* @param seq The sequence number to set
|
||
* @return The deserialized objects
|
||
*/
|
||
std::pair<std::shared_ptr<xrpl::STTx const>, std::shared_ptr<xrpl::TxMeta const>>
|
||
deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs, std::uint32_t seq);
|
||
|
||
/**
|
||
* @brief Convert a TransactionAndMetadata to two JSON objects
|
||
*
|
||
* @param blobs The TransactionAndMetadata to convert
|
||
* @param apiVersion The api version to generate the JSON for
|
||
* @param nftEnabled Whether to include NFT information in the JSON
|
||
* @param networkId The network ID to use for ctid, not include ctid if nullopt
|
||
* @return The JSON objects
|
||
*/
|
||
std::pair<boost::json::object, boost::json::object>
|
||
toExpandedJson(
|
||
data::TransactionAndMetadata const& blobs,
|
||
std::uint32_t apiVersion,
|
||
NFTokenjson nftEnabled = NFTokenjson::DISABLE,
|
||
std::optional<uint16_t> networkId = std::nullopt
|
||
);
|
||
|
||
/**
|
||
* @brief Convert a TransactionAndMetadata to JSON object containing tx and metadata data in hex
|
||
* format. According to the apiVersion, the key is "tx_blob" and "meta" or "meta_blob".
|
||
* @param txnPlusMeta The TransactionAndMetadata to convert.
|
||
* @param apiVersion The api version
|
||
* @return The JSON object containing tx and metadata data in hex format.
|
||
*/
|
||
boost::json::object
|
||
toJsonWithBinaryTx(data::TransactionAndMetadata const& txnPlusMeta, std::uint32_t apiVersion);
|
||
|
||
/**
|
||
* @brief Add "DeliverMax" which is the alias of "Amount" for "Payment" transaction to transaction
|
||
* json. Remove the "Amount" field when version is greater than 1
|
||
* @param txJson The transaction json object
|
||
* @param apiVersion The api version
|
||
*/
|
||
void
|
||
insertDeliverMaxAlias(boost::json::object& txJson, std::uint32_t apiVersion);
|
||
|
||
/**
|
||
* @brief Add "DeliveredAmount" to the transaction json object
|
||
*
|
||
* @param metaJson The metadata json object to add "DeliveredAmount"
|
||
* @param txn The transaction object
|
||
* @param meta The metadata object
|
||
* @param date The date of the ledger
|
||
* @return true if the "DeliveredAmount" is added to the metadata json object
|
||
*/
|
||
bool
|
||
insertDeliveredAmount(
|
||
boost::json::object& metaJson,
|
||
std::shared_ptr<xrpl::STTx const> const& txn,
|
||
std::shared_ptr<xrpl::TxMeta const> const& meta,
|
||
uint32_t date
|
||
);
|
||
|
||
/**
|
||
* @brief Add "mpt_issuance_id" into various MPTToken transaction json.
|
||
* @note We add "mpt_issuance_id" into the meta part of MPTokenIssuanceCreate only. The reason is
|
||
* because the mpt_issuance_id is generated only after one submits MPTokenIssuanceCreate, so there’s
|
||
* no way to know what the id is. (rippled)
|
||
*
|
||
* @param txnJson The transaction Json object
|
||
* @param txn The txn object
|
||
* @param metaJson The metadata Json object
|
||
* @param meta The metadata object
|
||
* @return true if the "mpt_issuance_id" is added to either txnJson or metaJson object
|
||
*/
|
||
bool
|
||
insertMPTIssuanceID(
|
||
boost::json::object& txnJson,
|
||
std::shared_ptr<xrpl::STTx const> const& txn,
|
||
boost::json::object& metaJson,
|
||
std::shared_ptr<xrpl::TxMeta const> const& meta
|
||
);
|
||
|
||
/**
|
||
* @brief Convert STBase object to JSON
|
||
*
|
||
* @param obj The object to convert
|
||
* @return The JSON object
|
||
*/
|
||
boost::json::object
|
||
toJson(xrpl::STBase const& obj);
|
||
|
||
/**
|
||
* @brief Convert SLE to JSON
|
||
*
|
||
* @param sle The ledger entry to convert
|
||
* @return The JSON object
|
||
*/
|
||
boost::json::object
|
||
toJson(xrpl::SLE const& sle);
|
||
|
||
/**
|
||
* @brief Convert a LedgerHeader to JSON object.
|
||
*
|
||
* @param info The LedgerHeader to convert.
|
||
* @param binary Whether to convert in hex format.
|
||
* @param apiVersion The api version
|
||
* @return The JSON object.
|
||
*/
|
||
boost::json::object
|
||
toJson(xrpl::LedgerHeader const& info, bool binary, std::uint32_t apiVersion);
|
||
|
||
/**
|
||
* @brief Convert a TxMeta to JSON object.
|
||
*
|
||
* @param meta The TxMeta to convert.
|
||
* @return The JSON object.
|
||
*/
|
||
boost::json::object
|
||
toJson(xrpl::TxMeta const& meta);
|
||
|
||
using RippledJson = json::Value;
|
||
|
||
/**
|
||
* @brief Convert a RippledJson to boost::json::value
|
||
*
|
||
* @param value The RippledJson to convert
|
||
* @return The JSON value
|
||
*/
|
||
boost::json::value
|
||
toBoostJson(RippledJson const& value);
|
||
|
||
/**
|
||
* @brief Generate a JSON object to publish ledger message
|
||
*
|
||
* @param lgrInfo The ledger header
|
||
* @param fees The fees
|
||
* @param ledgerRange The ledger range
|
||
* @param txnCount The transaction count
|
||
* @return The JSON object
|
||
*/
|
||
boost::json::object
|
||
generatePubLedgerMessage(
|
||
xrpl::LedgerHeader const& lgrInfo,
|
||
xrpl::Fees const& fees,
|
||
std::string const& ledgerRange,
|
||
std::uint32_t txnCount
|
||
);
|
||
|
||
/**
|
||
* @brief Get ledger info from the request
|
||
*
|
||
* @param backend The backend to use
|
||
* @param ctx The context of the request
|
||
* @return The ledger info or an error status
|
||
*/
|
||
std::expected<xrpl::LedgerHeader, Status>
|
||
ledgerHeaderFromRequest(
|
||
std::shared_ptr<data::BackendInterface const> const& backend,
|
||
web::Context const& ctx
|
||
);
|
||
|
||
/**
|
||
* @brief Get ledger info from hash or sequence
|
||
*
|
||
* @param backend The backend to use
|
||
* @param yield The coroutine context
|
||
* @param ledgerHash The optional ledger hash
|
||
* @param ledgerIndex The optional ledger index
|
||
* @param maxSeq The maximum sequence to search
|
||
* @return The ledger info or an error status
|
||
*/
|
||
std::expected<xrpl::LedgerHeader, Status>
|
||
getLedgerHeaderFromHashOrSeq(
|
||
BackendInterface const& backend,
|
||
boost::asio::yield_context yield,
|
||
std::optional<std::string> ledgerHash,
|
||
std::optional<uint32_t> ledgerIndex,
|
||
uint32_t maxSeq
|
||
);
|
||
|
||
/**
|
||
* @brief Traverse nodes owned by an account
|
||
*
|
||
* @param backend The backend to use
|
||
* @param owner The keylet of the owner
|
||
* @param hexMarker The marker
|
||
* @param startHint The start hint
|
||
* @param sequence The sequence
|
||
* @param limit The limit of nodes to traverse
|
||
* @param yield The coroutine context
|
||
* @param atOwnedNode The function to call for each owned node
|
||
* @return The status or the account cursor
|
||
*/
|
||
std::expected<AccountCursor, Status>
|
||
traverseOwnedNodes(
|
||
BackendInterface const& backend,
|
||
xrpl::Keylet const& owner,
|
||
xrpl::uint256 const& hexMarker,
|
||
std::uint32_t startHint,
|
||
std::uint32_t sequence,
|
||
std::uint32_t limit,
|
||
boost::asio::yield_context yield,
|
||
std::function<void(xrpl::SLE)> atOwnedNode
|
||
);
|
||
|
||
/**
|
||
* @brief Traverse nodes owned by an account
|
||
*
|
||
* @note Like the other one but removes the account check
|
||
*
|
||
* @param backend The backend to use
|
||
* @param accountID The account ID
|
||
* @param sequence The sequence
|
||
* @param limit The limit of nodes to traverse
|
||
* @param jsonCursor The optional JSON cursor
|
||
* @param yield The coroutine context
|
||
* @param atOwnedNode The function to call for each owned node
|
||
* @param nftIncluded Whether to include NFTs
|
||
* @return The status or the account cursor
|
||
*/
|
||
std::expected<AccountCursor, Status>
|
||
traverseOwnedNodes(
|
||
BackendInterface const& backend,
|
||
xrpl::AccountID const& accountID,
|
||
std::uint32_t sequence,
|
||
std::uint32_t limit,
|
||
std::optional<std::string> jsonCursor,
|
||
boost::asio::yield_context yield,
|
||
std::function<void(xrpl::SLE)> atOwnedNode,
|
||
bool nftIncluded = false
|
||
);
|
||
|
||
/**
|
||
* @brief Read SLE from the backend
|
||
*
|
||
* @param backend The backend to use
|
||
* @param keylet The keylet to read
|
||
* @param lgrInfo The ledger header
|
||
* @param context The context of the request
|
||
* @return The SLE or nullptr if not found
|
||
*/
|
||
std::shared_ptr<xrpl::SLE const>
|
||
read(
|
||
std::shared_ptr<data::BackendInterface const> const& backend,
|
||
xrpl::Keylet const& keylet,
|
||
xrpl::LedgerHeader const& lgrInfo,
|
||
web::Context const& context
|
||
);
|
||
|
||
/**
|
||
* @brief Get the account associated with a transaction
|
||
*
|
||
* @param transaction The transaction
|
||
* @return A vector of accounts associated with the transaction
|
||
*/
|
||
std::vector<xrpl::AccountID>
|
||
getAccountsFromTransaction(boost::json::object const& transaction);
|
||
|
||
/**
|
||
* @brief Convert a ledger header to a blob
|
||
*
|
||
* @param info The ledger header
|
||
* @param includeHash Whether to include the hash
|
||
* @return The blob
|
||
*/
|
||
std::vector<unsigned char>
|
||
ledgerHeaderToBlob(xrpl::LedgerHeader const& info, bool includeHash = false);
|
||
|
||
/**
|
||
* @brief Whether global frozen is set
|
||
*
|
||
* @param backend The backend to use
|
||
* @param seq The ledger sequence
|
||
* @param issuer The issuer
|
||
* @param yield The coroutine context
|
||
* @return true if the global frozen is set; false otherwise
|
||
*/
|
||
bool
|
||
isGlobalFrozen(
|
||
BackendInterface const& backend,
|
||
std::uint32_t seq,
|
||
xrpl::AccountID const& issuer,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Whether the account is frozen
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param account The account
|
||
* @param currency The currency
|
||
* @param issuer The issuer
|
||
* @param yield The coroutine context
|
||
* @return true if the account is frozen; false otherwise
|
||
*/
|
||
bool
|
||
isFrozen(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& account,
|
||
xrpl::Currency const& currency,
|
||
xrpl::AccountID const& issuer,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Fetches a ledger object and checks if any of the specified flag is set on the account.
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param keylet The keylet representing the object
|
||
* @param flags The flags to check on the fetched `SLE`.
|
||
* @param yield The coroutine context
|
||
* @return true if any of the flag in flags are set for this account; false otherwise
|
||
*/
|
||
bool
|
||
fetchAndCheckAnyFlagsExists(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::Keylet const& keylet,
|
||
std::vector<std::uint32_t> const& flags,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Whether the trustline is deep frozen.
|
||
*
|
||
* For deep freeze, (unlike regular freeze) we do not care which account has the high/low deep
|
||
* freeze flag. We only care about if the trustline is deep frozen or not.
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param account The account
|
||
* @param currency The currency
|
||
* @param issuer The issuer
|
||
* @param yield The coroutine context
|
||
* @return true if the account is deep frozen; false otherwise
|
||
*/
|
||
bool
|
||
isDeepFrozen(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& account,
|
||
xrpl::Currency const& currency,
|
||
xrpl::AccountID const& issuer,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Whether the account that owns a LPToken is frozen for the assets in the pool
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param account The account
|
||
* @param asset The first asset in the pool
|
||
* @param asset2 The second asset in the pool
|
||
* @param yield The coroutine context
|
||
* @return true if account is frozen for one of the assets
|
||
*/
|
||
bool
|
||
isLPTokenFrozen(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& account,
|
||
xrpl::Issue const& asset,
|
||
xrpl::Issue const& asset2,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Get the account funds
|
||
*
|
||
* @param backend The backend to use
|
||
* @param amendmentCenter The amendmentCenter to use
|
||
* @param sequence The sequence
|
||
* @param amount The amount
|
||
* @param id The account ID
|
||
* @param yield The coroutine context
|
||
* @return The account funds
|
||
*/
|
||
xrpl::STAmount
|
||
accountFunds(
|
||
BackendInterface const& backend,
|
||
data::AmendmentCenterInterface const& amendmentCenter,
|
||
std::uint32_t sequence,
|
||
xrpl::STAmount const& amount,
|
||
xrpl::AccountID const& id,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Get the amount that an account holds
|
||
*
|
||
* @param backend The backend to use
|
||
* @param amendmentCenter The amendmentCenter to use
|
||
* @param sequence The sequence
|
||
* @param account The account
|
||
* @param currency The currency
|
||
* @param issuer The issuer
|
||
* @param zeroIfFrozen Whether to return zero if frozen
|
||
* @param yield The coroutine context
|
||
* @return The amount account holds
|
||
*/
|
||
xrpl::STAmount
|
||
accountHolds(
|
||
BackendInterface const& backend,
|
||
data::AmendmentCenterInterface const& amendmentCenter,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& account,
|
||
xrpl::Currency const& currency,
|
||
xrpl::AccountID const& issuer,
|
||
bool zeroIfFrozen,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Get the amount that an LPToken owner holds
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param account The account
|
||
* @param currency The currency
|
||
* @param issuer The issuer
|
||
* @param zeroIfFrozen Whether to return zero if frozen
|
||
* @param yield The coroutine context
|
||
* @return The amount account holds
|
||
*/
|
||
xrpl::STAmount
|
||
ammAccountHolds(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& account,
|
||
xrpl::Currency const& currency,
|
||
xrpl::AccountID const& issuer,
|
||
bool const zeroIfFrozen,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Get the transfer rate
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param issuer The issuer
|
||
* @param yield The coroutine context
|
||
* @return The transfer rate
|
||
*/
|
||
xrpl::Rate
|
||
transferRate(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& issuer,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Get the XRP liquidity
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param id The account ID
|
||
* @param yield The coroutine context
|
||
* @return The XRP liquidity
|
||
*/
|
||
xrpl::XRPAmount
|
||
xrpLiquid(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& id,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Post process an order book
|
||
*
|
||
* @param offers The offers
|
||
* @param book The book
|
||
* @param takerID The taker ID
|
||
* @param backend The backend to use
|
||
* @param amendmentCenter The amendmentCenter to use
|
||
* @param ledgerSequence The ledger sequence
|
||
* @param yield The coroutine context
|
||
* @return The post processed order book
|
||
*/
|
||
boost::json::array
|
||
postProcessOrderBook(
|
||
std::vector<data::LedgerObject> const& offers,
|
||
xrpl::Book const& book,
|
||
xrpl::AccountID const& takerID,
|
||
data::BackendInterface const& backend,
|
||
data::AmendmentCenterInterface const& amendmentCenter,
|
||
std::uint32_t ledgerSequence,
|
||
boost::asio::yield_context yield
|
||
);
|
||
|
||
/**
|
||
* @brief Parse the book from the request
|
||
*
|
||
* @param pays The currency to pay
|
||
* @param payIssuer The issuer of the currency to pay
|
||
* @param gets The currency to get
|
||
* @param getIssuer The issuer of the currency to get
|
||
* @param domain The domain
|
||
* @return The book or an error status
|
||
*/
|
||
std::expected<xrpl::Book, Status>
|
||
parseBook(
|
||
xrpl::Currency pays,
|
||
xrpl::AccountID payIssuer,
|
||
xrpl::Currency gets,
|
||
xrpl::AccountID getIssuer,
|
||
std::optional<std::string> const& domain
|
||
);
|
||
|
||
/**
|
||
* @brief Parse the book from the request
|
||
*
|
||
* @param request The request
|
||
* @return The book or an error status
|
||
*/
|
||
std::expected<xrpl::Book, Status>
|
||
parseBook(boost::json::object const& request);
|
||
|
||
/**
|
||
* @brief Parse the taker from the request
|
||
*
|
||
* @param taker The taker as json
|
||
* @return The taker account or an error status
|
||
*/
|
||
std::expected<xrpl::AccountID, Status>
|
||
parseTaker(boost::json::value const& taker);
|
||
|
||
/**
|
||
* @brief Parse the json object into a xrpl::Issue object.
|
||
* @param issue The json object to parse. The accepted format is { "currency" : "USD", "issuer" :
|
||
* "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59" } or {"currency" : "XRP"}
|
||
* @return The xrpl::Issue object.
|
||
* @exception raise json::error exception if the json object is not in the accepted format.
|
||
*/
|
||
xrpl::Issue
|
||
parseIssue(boost::json::object const& issue);
|
||
|
||
/**
|
||
* @brief Check whether the request specifies the `current` or `closed` ledger
|
||
* @param request The request to check
|
||
* @return true if the request specifies the `current` or `closed` ledger
|
||
*/
|
||
bool
|
||
specifiesCurrentOrClosedLedger(boost::json::object const& request);
|
||
|
||
/**
|
||
* @brief Check whether a request requires administrative privileges on rippled side.
|
||
*
|
||
* @param method The method name to check
|
||
* @param request The request to check
|
||
* @return true if the request requires ADMIN role
|
||
*/
|
||
bool
|
||
isAdminCmd(std::string const& method, boost::json::object const& request);
|
||
|
||
/**
|
||
* @brief Get the NFTID from the request
|
||
*
|
||
* @param request The request
|
||
* @return The NFTID or an error status
|
||
*/
|
||
std::expected<xrpl::uint256, Status>
|
||
getNFTID(boost::json::object const& request);
|
||
|
||
/**
|
||
* @brief Encode CTID as string
|
||
*
|
||
* @param ledgerSeq The ledger sequence
|
||
* @param txnIndex The transaction index
|
||
* @param networkId The network ID
|
||
* @return The encoded CTID or std::nullopt if the input is invalid
|
||
*/
|
||
std::optional<std::string>
|
||
encodeCTID(uint32_t ledgerSeq, uint16_t txnIndex, uint16_t networkId) noexcept;
|
||
|
||
/**
|
||
* @brief Decode the CTID from a string or a uint64_t
|
||
*
|
||
* @tparam T The type of the CTID
|
||
* @param ctid The CTID to decode
|
||
* @return The decoded CTID
|
||
*/
|
||
template <typename T>
|
||
inline std::optional<std::tuple<uint32_t, uint16_t, uint16_t>>
|
||
decodeCTID(T const ctid) noexcept
|
||
{
|
||
auto const getCTID64 = [](T const ctid) noexcept -> std::optional<uint64_t> {
|
||
if constexpr (std::is_convertible_v<T, std::string>) {
|
||
std::string const ctidString(ctid);
|
||
static constexpr std::size_t kCtidStringLength = 16;
|
||
if (ctidString.length() != kCtidStringLength)
|
||
return {};
|
||
|
||
if (!boost::regex_match(ctidString, boost::regex("^[0-9A-F]+$")))
|
||
return {};
|
||
|
||
return std::stoull(ctidString, nullptr, 16);
|
||
}
|
||
|
||
if constexpr (std::is_same_v<T, uint64_t>)
|
||
return ctid;
|
||
|
||
return {};
|
||
};
|
||
|
||
auto const ctidValue = getCTID64(ctid).value_or(0);
|
||
|
||
static constexpr uint64_t kCtidPrefix = 0xC000'0000'0000'0000ULL;
|
||
static constexpr uint64_t kCtidPrefixMask = 0xF000'0000'0000'0000ULL;
|
||
|
||
if ((ctidValue & kCtidPrefixMask) != kCtidPrefix)
|
||
return {};
|
||
|
||
uint32_t const ledgerSeq = (ctidValue >> 32) & 0xFFFF'FFFUL;
|
||
uint16_t const txnIndex = (ctidValue >> 16) & 0xFFFFU;
|
||
uint16_t const networkId = ctidValue & 0xFFFFU;
|
||
return {{ledgerSeq, txnIndex, networkId}};
|
||
}
|
||
|
||
/**
|
||
* @brief Log the duration of the request processing
|
||
*
|
||
* @tparam T The type of the duration
|
||
* @param request The request to log
|
||
* @param tag The tag of the context of the request
|
||
* @param dur The duration to log
|
||
*/
|
||
template <typename DurationType>
|
||
void
|
||
logDuration(
|
||
boost::json::object const& request,
|
||
util::BaseTagDecorator const& tag,
|
||
DurationType const& dur
|
||
)
|
||
{
|
||
using boost::json::serialize;
|
||
|
||
static util::Logger const log{"RPC"}; // NOLINT(readability-identifier-naming)
|
||
static constexpr std::int64_t kDurationErrorThresholdSeconds = 10;
|
||
|
||
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
|
||
auto const seconds = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
|
||
auto const msg = fmt::format(
|
||
"Request processing duration = {} milliseconds. request = {}",
|
||
millis,
|
||
serialize(util::removeSecret(request))
|
||
);
|
||
|
||
if (seconds > kDurationErrorThresholdSeconds) {
|
||
LOG(log.error()) << tag << msg;
|
||
} else if (seconds > 1) {
|
||
LOG(log.warn()) << tag << msg;
|
||
} else {
|
||
LOG(log.info()) << tag << msg;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Parse a ripple-lib seed
|
||
*
|
||
* @param value JSON value to parse from
|
||
* @return The parsed seed if successful; std::nullopt otherwise
|
||
*/
|
||
std::optional<xrpl::Seed>
|
||
parseRippleLibSeed(boost::json::value const& value);
|
||
|
||
/**
|
||
* @brief Traverse NFT objects and call the callback for each owned node
|
||
*
|
||
* @param backend The backend to use
|
||
* @param sequence The sequence
|
||
* @param accountID The account ID
|
||
* @param nextPage The next page
|
||
* @param limit The limit
|
||
* @param yield The coroutine context
|
||
* @param atOwnedNode The function to call for each owned node
|
||
* @return The account cursor or an error status
|
||
*/
|
||
std::expected<AccountCursor, Status>
|
||
traverseNFTObjects(
|
||
BackendInterface const& backend,
|
||
std::uint32_t sequence,
|
||
xrpl::AccountID const& accountID,
|
||
xrpl::uint256 nextPage,
|
||
std::uint32_t limit,
|
||
boost::asio::yield_context yield,
|
||
std::function<void(xrpl::SLE)> atOwnedNode
|
||
);
|
||
|
||
/**
|
||
* @brief Parse the string as a uint32_t
|
||
*
|
||
* @param value The string to parse
|
||
* @return The parsed value or std::nullopt if the string is not a valid uint32_t
|
||
*/
|
||
std::optional<std::uint32_t>
|
||
parseStringAsUInt(std::string const& value); // TODO: move to string utils or something?
|
||
|
||
/**
|
||
* @brief Whether the transaction can have a delivered amount
|
||
*
|
||
* @param txn The transaction
|
||
* @param meta The metadata
|
||
* @return true if the transaction can have a delivered amount
|
||
*/
|
||
bool
|
||
canHaveDeliveredAmount(
|
||
std::shared_ptr<xrpl::STTx const> const& txn,
|
||
std::shared_ptr<xrpl::TxMeta const> const& meta
|
||
);
|
||
|
||
/**
|
||
* @brief Get the delivered amount
|
||
*
|
||
* @param txn The transaction
|
||
* @param meta The metadata
|
||
* @param ledgerSequence The sequence
|
||
* @param date The date of the ledger
|
||
* @return The delivered amount or std::nullopt if not available
|
||
*/
|
||
std::optional<xrpl::STAmount>
|
||
getDeliveredAmount(
|
||
std::shared_ptr<xrpl::STTx const> const& txn,
|
||
std::shared_ptr<xrpl::TxMeta const> const& meta,
|
||
std::uint32_t ledgerSequence,
|
||
uint32_t date
|
||
);
|
||
|
||
} // namespace rpc
|