feat: Support filtering txns by mpt_issuance_id (#3153)

Adds an optional `mpt_issuance_id ` field to Account_tx so that users
can filter Account transactions if the transaction is involved in a
specific `mpt_issuance_id `
This commit is contained in:
Peter Chen
2026-08-04 12:22:43 -04:00
committed by GitHub
parent 6ce668f493
commit 466b60f8ea
7 changed files with 365 additions and 1 deletions

View File

@@ -155,6 +155,25 @@ getMPTokenIssuanceTxsFromTx(xrpl::TxMeta const& txMeta, xrpl::STTx const& sttx)
return result;
}
bool
referencesMptIssuance(
xrpl::TxMeta const& txMeta,
xrpl::STTx const& sttx,
xrpl::uint192 const& mptIssuanceID
)
{
if (txMeta.getResultTER() == xrpl::tesSUCCESS) {
for (auto const& node : txMeta.getNodes()) {
if (getMPTokenIssuanceIDFromNode(node) == mptIssuanceID)
return true;
}
}
MPTokenIssuanceIDs issuanceIDs;
addMPTokenIssuanceIDsFromTx(issuanceIDs, sttx);
return issuanceIDs.contains(mptIssuanceID);
}
std::optional<MPTHolderData>
getMPTHolderFromObj(std::string const& key, std::string const& blob)
{

View File

@@ -3,6 +3,7 @@
#include "data/DBHelpers.hpp"
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/TxMeta.h>
@@ -51,4 +52,23 @@ getMPTHolderFromObj(std::string const& key, std::string const& blob);
std::vector<MPTokenIssuanceTransactionsData>
getMPTokenIssuanceTxsFromTx(xrpl::TxMeta const& txMeta, xrpl::STTx const& sttx);
/**
* @brief Check whether a transaction references a specific MPT issuance.
*
* @note Scans the same sources as getMPTokenIssuanceTxsFromTx (metadata's affected
* MPTokenIssuance/MPToken nodes, and the transaction's own MPTokenIssuanceID/MPT issue fields), but
* exits as soon as a match is found instead of collecting every distinct issuance touched.
*
* @param txMeta Transaction metadata.
* @param sttx The transaction.
* @param mptIssuanceID The MPT issuance to check for.
* @return true if the transaction references mptIssuanceID.
*/
bool
referencesMptIssuance(
xrpl::TxMeta const& txMeta,
xrpl::STTx const& sttx,
xrpl::uint192 const& mptIssuanceID
);
} // namespace etl

View File

@@ -58,4 +58,4 @@ target_sources(
handlers/VaultInfo.cpp
)
target_link_libraries(clio_rpc PUBLIC clio_util clio_data)
target_link_libraries(clio_rpc PUBLIC clio_util clio_data clio_etl)

View File

@@ -1,6 +1,7 @@
#include "rpc/handlers/AccountTx.hpp"
#include "data/Types.hpp"
#include "etl/MPTHelpers.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/RPCHelpers.hpp"
@@ -16,6 +17,7 @@
#include <boost/json/value.hpp>
#include <boost/json/value_from.hpp>
#include <boost/json/value_to.hpp>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/protocol/AccountID.h>
@@ -128,6 +130,10 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c
if (retCursor)
response.marker = {.ledger = retCursor->ledgerSequence, .seq = retCursor->transactionIndex};
std::optional<xrpl::uint192> mptIssuanceFilter;
if (input.mptIssuanceId)
mptIssuanceFilter = xrpl::uint192{input.mptIssuanceId->c_str()};
for (auto const& txnPlusMeta : blobs) {
// over the range
if ((txnPlusMeta.ledgerSequence < minIndex && !input.forward) ||
@@ -142,6 +148,14 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c
boost::json::object obj;
// Skip all Txns where the specified filter mpt_id doesn't match the query
if (mptIssuanceFilter) {
auto const [sttx, txMeta] =
deserializeTxPlusMeta(txnPlusMeta, txnPlusMeta.ledgerSequence);
if (!etl::referencesMptIssuance(*txMeta, *sttx, *mptIssuanceFilter))
continue;
}
// if binary is false or transactionType is specified, we need to expand the transaction
if (!input.binary || input.transactionTypeInLowercase.has_value()) {
auto [txn, meta] = toExpandedJson(txnPlusMeta, ctx.apiVersion, NFTokenjson::ENABLE);
@@ -298,6 +312,11 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
boost::json::value_to<std::string>(jsonObject.at("tx_type"));
}
if (jsonObject.contains(JS(mpt_issuance_id))) {
input.mptIssuanceId =
boost::json::value_to<std::string>(jsonObject.at(JS(mpt_issuance_id)));
}
return input;
}

View File

@@ -85,6 +85,7 @@ public:
std::optional<uint32_t> limit;
std::optional<Marker> marker;
std::optional<std::string> transactionTypeInLowercase;
std::optional<std::string> mptIssuanceId;
};
using Result = HandlerReturnType<Output>;
@@ -141,6 +142,7 @@ public:
typesKeysInLowercase.cbegin(), typesKeysInLowercase.cend()
),
},
{JS(mpt_issuance_id), validation::CustomValidators::uint192HexStringValidator},
};
static auto const kRpcSpec = RpcSpec{

View File

@@ -17,6 +17,7 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STInteger.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/jss.h>