Compare commits

..

5 Commits

Author SHA1 Message Date
Ayaz Salikhov
c64681704e chore: Merge develop into release/2.8.0 (#3186) 2026-08-20 15:59:46 +01:00
Ayaz Salikhov
e6c91a1572 fix: Use credentialTypeValidator in LedgerEntry (#3185) 2026-08-20 15:57:56 +01:00
Alex Kremer
4f884e3b4b fix: Better validator for issuer (#3184) 2026-08-20 15:57:46 +01:00
Ayaz Salikhov
8e091871cb chore: Revert "feat: Add mptoken_issuance_history RPC" (#3183) 2026-08-20 15:42:22 +01:00
Bryan
e8e0478333 feat: Add mptoken_issuance_history RPC (#3141)
feat: add mptoken_issuance_history RPC

Summary

Adds mptoken_issuance_history, a Clio-only method that returns the
transaction history for a given MPT issuance — the MPT-scoped sibling of
nft_history. You can optionally filter by account and/or tx_type.

The index tables, backend fetch methods, and live ETL indexing landed
earlier; this wires up the handler on top of them.

The handler

- Routes to fetchMPTokenIssuanceTransactions or
fetchAccountMPTokenIssuanceTransactions depending on whether account is
set. When tx_type is given, it filters on TransactionType post-fetch,
exactly like account_tx.
- Follows the nft_history/account_tx conventions for ledger ranges,
markers, binary, forward, and limit ([1,100], default 50), including
api-version response branching.
- Gated on backfill completion so it never returns partial history:
until this node's MPTTransactionHistoryMigrator reports Migrated,
requests get notReady with a message pointing at the --migrate command.
Once migrated, the result is cached and the check is skipped — the
method turns on automatically, no restart.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 09:43:06 -07:00
5 changed files with 36 additions and 8 deletions

View File

@@ -363,7 +363,7 @@ CustomValidator CustomValidators::authorizeCredentialValidator =
}
// don't want to change issuer error message to be about credentials
if (!issuerValidator.verify(credObj, "issuer")) {
if (!accountBase58Validator.verify(credObj, "issuer")) {
return Error{
Status{ClioError::RpcMalformedAuthorizedCredentials, "issuer NotString"}
};

View File

@@ -590,7 +590,8 @@ struct CustomValidators final {
/**
* @brief Provides a validator for validating credential_type.
*
* Used by AuthorizeCredentialValidator in deposit_preauth.
* Used by AuthorizeCredentialValidator in deposit_preauth and by the credential
* object lookup in ledger_entry.
*/
static CustomValidator credentialTypeValidator;
};

View File

@@ -13,6 +13,7 @@
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <xrpl/basics/Blob.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/base_uint.h>
@@ -32,6 +33,7 @@
#include <algorithm>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
@@ -422,20 +424,23 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
return xrpl::keylet::oracle(*account, documentId).key;
};
auto const parseCredentialFromJson = [](boost::json::value const& json) {
auto const parseCredentialFromJson =
[](boost::json::value const& json) -> std::optional<xrpl::uint256> {
auto const subject = util::parseBase58Wrapper<xrpl::AccountID>(
boost::json::value_to<std::string>(json.at(JS(subject)))
);
auto const issuer = util::parseBase58Wrapper<xrpl::AccountID>(
boost::json::value_to<std::string>(json.at(JS(issuer)))
);
auto const credType =
auto const credTypeOpt =
xrpl::strUnHex(boost::json::value_to<std::string>(json.at(JS(credential_type))));
return xrpl::keylet::credential(
*subject, *issuer, xrpl::Slice(credType->data(), credType->size())
)
.key;
return credTypeOpt.transform([&](xrpl::Blob const& credType) -> xrpl::uint256 {
return xrpl::keylet::credential(
*subject, *issuer, xrpl::Slice(credType.data(), credType.size())
)
.key;
});
};
auto const indexFieldType =

View File

@@ -380,6 +380,7 @@ public:
meta::WithCustomError{
validation::Type<std::string>{}, Status(ClioError::RpcMalformedRequest)
},
validation::CustomValidators::credentialTypeValidator,
},
}}},
{JS(mpt_issuance),

View File

@@ -347,6 +347,27 @@ generateTestValuesForParametersTest()
.expectedErrorMessage = "issuer NotString"
},
ParamTestCaseBundle{
.testName = "DepositPreauthAuthorizeCredentialsHexIssuer",
.testJson = fmt::format(
R"JSON({{
"deposit_preauth": {{
"owner": "{}",
"authorized_credentials": [
{{
"issuer": "0000000000000000000000000000000000000002",
"credential_type": "{}"
}}
]
}}
}})JSON",
kAccount,
kCredentialType
),
.expectedError = "malformedAuthorizedCredentials",
.expectedErrorMessage = "issuer NotString"
},
ParamTestCaseBundle{
.testName = "DepositPreauthAuthorizeCredentialsIncorrectCredentialType",
.testJson = fmt::format(