From 8336f0473f3b1936443d4a55dbc38be237610191 Mon Sep 17 00:00:00 2001 From: JCW Date: Mon, 17 Aug 2026 13:11:51 +0100 Subject: [PATCH 1/3] Stop checking pseudo account fields --- include/xrpl/ledger/helpers/AccountRootHelpers.h | 14 +++++--------- src/libxrpl/ledger/helpers/AccountRootHelpers.cpp | 13 ++++--------- src/libxrpl/ledger/helpers/MPTokenHelpers.cpp | 3 +-- src/libxrpl/tx/invariants/MPTInvariant.cpp | 2 +- .../tx/transactors/token/MPTokenAuthorize.cpp | 2 +- 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/include/xrpl/ledger/helpers/AccountRootHelpers.h b/include/xrpl/ledger/helpers/AccountRootHelpers.h index 350fc6ca85c..5c9c89a2192 100644 --- a/include/xrpl/ledger/helpers/AccountRootHelpers.h +++ b/include/xrpl/ledger/helpers/AccountRootHelpers.h @@ -15,7 +15,6 @@ #include #include #include -#include #include namespace xrpl { @@ -359,8 +358,8 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); getPseudoAccountFields(); /** - * Returns true if and only if sleAcct is a pseudo-account or specific - * pseudo-accounts in pseudoFieldFilter. + * Returns true if and only if sleAcct is a pseudo-account of any kind + * (i.e. carries at least one field flagged with SField::sMD_PseudoAccount). * * Returns false if sleAcct is: * - NOT a pseudo-account OR @@ -368,18 +367,15 @@ getPseudoAccountFields(); * - null pointer */ [[nodiscard]] bool -isPseudoAccount(SLE::const_pointer sleAcct, std::set const& pseudoFieldFilter = {}); +isPseudoAccount(SLE::const_pointer sleAcct); /** * Convenience overload that reads the account from the view. */ [[nodiscard]] inline bool -isPseudoAccount( - ReadView const& view, - AccountID const& accountId, - std::set const& pseudoFieldFilter = {}) +isPseudoAccount(ReadView const& view, AccountID const& accountId) { - return isPseudoAccount(view.read(keylet::account(accountId)), pseudoFieldFilter); + return isPseudoAccount(view.read(keylet::account(accountId))); } /** diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index faca4ebfb6b..a555be3bc19 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -547,18 +546,14 @@ getPseudoAccountFields() } [[nodiscard]] bool -isPseudoAccount(SLE::const_pointer sleAcct, std::set const& pseudoFieldFilter) +isPseudoAccount(SLE::const_pointer sleAcct) { - auto const& fields = getPseudoAccountFields(); - // Intentionally use defensive coding here because it's cheap and makes the // semantics of true return value clean. return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT && - std::count_if( - fields.begin(), fields.end(), [&sleAcct, &pseudoFieldFilter](SField const* sf) -> bool { - return sleAcct->isFieldPresent(*sf) && - (pseudoFieldFilter.empty() || pseudoFieldFilter.contains(sf)); - }) > 0; + std::ranges::any_of(getPseudoAccountFields(), [&sleAcct](SField const* sf) { + return sleAcct->isFieldPresent(*sf); + }); } std::expected diff --git a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp index b239d0d3d11..a5455a8de38 100644 --- a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp +++ b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp @@ -332,8 +332,7 @@ requireAuth( // They are implicitly authorized for any MPT they hold, including vault shares whose // underlying asset would otherwise require auth. auto const isPseudoAccountExempt = [&] { - return (featureSAVEnabled || featureMPTV2Enabled) && - isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID, &sfAMMID}); + return (featureSAVEnabled || featureMPTV2Enabled) && isPseudoAccount(view, account); }; auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID()); diff --git a/src/libxrpl/tx/invariants/MPTInvariant.cpp b/src/libxrpl/tx/invariants/MPTInvariant.cpp index 12ec078c824..5e6c379af89 100644 --- a/src/libxrpl/tx/invariants/MPTInvariant.cpp +++ b/src/libxrpl/tx/invariants/MPTInvariant.cpp @@ -819,7 +819,7 @@ ValidMPTTransfer::isAuthorized( // auth. Exempt them here rather than relying on requireAuth: the recursive // share -> underlying descent in requireAuth fails for a pseudo-account // that holds the share but not the underlying. - if (isPseudoAccount(view, holder, {&sfVaultID, &sfLoanBrokerID, &sfAMMID})) + if (isPseudoAccount(view, holder)) return true; auto const key = keylet::mptoken(mptid, holder); diff --git a/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp b/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp index 0aeb6f33d19..2204f5ec910 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp @@ -153,7 +153,7 @@ MPTokenAuthorize::preclaim(PreclaimContext const& ctx) // always authorized. No need to amendment gate since Vault and LoanBroker // can only be created if the Vault amendment is enabled; AMM with MPToken asset // can only be created if MPTokensV2 is enabled. - if (isPseudoAccount(ctx.view, *holderID, {&sfVaultID, &sfLoanBrokerID, &sfAMMID})) + if (isPseudoAccount(ctx.view, *holderID)) return tecNO_PERMISSION; return tesSUCCESS; From 398e504b5811a4cb639ef181da9684035664d42a Mon Sep 17 00:00:00 2001 From: JCW Date: Wed, 19 Aug 2026 14:31:05 +0100 Subject: [PATCH 2/3] Address PR comments --- include/xrpl/ledger/helpers/AccountRootHelpers.h | 4 ++-- src/libxrpl/ledger/helpers/AccountRootHelpers.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xrpl/ledger/helpers/AccountRootHelpers.h b/include/xrpl/ledger/helpers/AccountRootHelpers.h index 5c9c89a2192..452d402d14c 100644 --- a/include/xrpl/ledger/helpers/AccountRootHelpers.h +++ b/include/xrpl/ledger/helpers/AccountRootHelpers.h @@ -352,14 +352,14 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); * * The list is constructed during initialization and is const after that. * Pseudo-account designator fields MUST be maintained by including the - * SField::sMD_PseudoAccount flag in the SField definition. + * SField::kSmdPseudoAccount flag in the SField definition. */ [[nodiscard]] std::vector const& getPseudoAccountFields(); /** * Returns true if and only if sleAcct is a pseudo-account of any kind - * (i.e. carries at least one field flagged with SField::sMD_PseudoAccount). + * (i.e. carries at least one field flagged with SField::kSmdPseudoAccount). * * Returns false if sleAcct is: * - NOT a pseudo-account OR diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index a555be3bc19..e0ead3e19a1 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -514,7 +514,7 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey) } // Pseudo-account designator fields MUST be maintained by including the -// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to +// SField::kSmdPseudoAccount flag in the SField definition. (Don't forget to // "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated, // since a non-active amendment will not set any field, by definition. // Specific properties of a pseudo-account are NOT checked here, that's what From 97b6ff78ee04e40271236f50d7b4484ded8bb578 Mon Sep 17 00:00:00 2001 From: Jingchen Date: Wed, 26 Aug 2026 19:14:13 +0100 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/libxrpl/ledger/helpers/AccountRootHelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index e0ead3e19a1..819ebb04d17 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -515,7 +515,7 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey) // Pseudo-account designator fields MUST be maintained by including the // SField::kSmdPseudoAccount flag in the SField definition. (Don't forget to -// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated, +// "| SField::kSmdDefault"!) The fields do NOT need to be amendment-gated, // since a non-active amendment will not set any field, by definition. // Specific properties of a pseudo-account are NOT checked here, that's what // InvariantCheck is for.