From 8d379087e5187bbb509dbceb0ed6d08a8d84a2f8 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 9 Jul 2026 20:04:30 -0400 Subject: [PATCH] small fixes (part 6) (#7782) --- .../ledger/helpers/AccountRootHelpers.cpp | 2 + src/libxrpl/ledger/helpers/SponsorHelpers.cpp | 7 ++- src/libxrpl/tx/Transactor.cpp | 4 +- src/libxrpl/tx/transactors/token/TrustSet.cpp | 46 +++++++++++-------- src/test/jtx/owners.h | 9 ++-- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index a5e9195a9c..60f358a136 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -79,12 +79,14 @@ confineOwnerCount( // Underflow is well defined on unsigned if (totalOwnerCount > currentOwnerCount) { + // LCOV_EXCL_START if (id) { JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!"; } totalOwnerCount = 0; XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set"); + // LCOV_EXCL_STOP } } return totalOwnerCount; diff --git a/src/libxrpl/ledger/helpers/SponsorHelpers.cpp b/src/libxrpl/ledger/helpers/SponsorHelpers.cpp index 48a37545f4..f421b10018 100644 --- a/src/libxrpl/ledger/helpers/SponsorHelpers.cpp +++ b/src/libxrpl/ledger/helpers/SponsorHelpers.cpp @@ -68,7 +68,7 @@ getTxReserveSponsor(ReadView const& view, STTx const& tx) // already checked in Transactor::checkSponsor if (!sle) - return std::unexpected(tecINTERNAL); + return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE return sle; } return SLE::pointer(); @@ -196,6 +196,9 @@ getLedgerEntryOwner(ReadView const& view, SLE const& sle, AccountID const& accou if (lowAccount == account) return lowAccount; } + // Reachable: the sponsee may be a third party or the side of the + // line that holds no reserve (e.g. the issuer). Callers map this + // to tecNO_PERMISSION. return std::nullopt; } default: @@ -248,8 +251,10 @@ getLedgerEntryOwnerCount(SLE const& sle) return 2 + static_cast(sle.getFieldArray(sfSignerEntries).size()); } case ltACCOUNT_ROOT: + // LCOV_EXCL_START UNREACHABLE("AccountRoots are not supported by object sponsorship."); return 0; + // LCOV_EXCL_STOP default: return 1; } diff --git a/src/libxrpl/tx/Transactor.cpp b/src/libxrpl/tx/Transactor.cpp index 679e3373e7..53d595df49 100644 --- a/src/libxrpl/tx/Transactor.cpp +++ b/src/libxrpl/tx/Transactor.cpp @@ -411,7 +411,7 @@ Transactor::checkSponsor(ReadView const& view, STTx const& tx) if (tx.isFieldPresent(sfDelegate) && isReserveSponsored(tx)) return temINVALID; - if (auto const sponsorSle = getTxReserveSponsor(view, tx); !sponsorSle) + if (!view.exists(keylet::account(tx.getAccountID(sfSponsor)))) return terNO_ACCOUNT; auto const hasSponsorSignature = tx.isFieldPresent(sfSponsorSignature); @@ -428,7 +428,7 @@ Transactor::checkSponsor(ReadView const& view, STTx const& tx) auto const sponsorshipSle = view.read(keylet::sponsorship(tx.getAccountID(sfSponsor), tx.getInitiator())); - // sponsorship object missing for pre-funded tx + // sponsorship object missing for pre-funded (no co-signing) tx if (!sponsorshipSle) return terNO_PERMISSION; diff --git a/src/libxrpl/tx/transactors/token/TrustSet.cpp b/src/libxrpl/tx/transactors/token/TrustSet.cpp index cf3454add1..9f79e5fb3a 100644 --- a/src/libxrpl/tx/transactors/token/TrustSet.cpp +++ b/src/libxrpl/tx/transactors/token/TrustSet.cpp @@ -528,17 +528,20 @@ TrustSet::doApply() { SLE::pointer const lowSponsor = getSponsor(uLowAccountID); - if (auto const ret = checkReserve( - ctx_.getApplyViewContext(), - sleLowAccount, - preFeeBalance_, - lowSponsor, - {.ownerCountDelta = 1}, - j_, - tecINSUF_RESERVE_LINE); - lowSponsor && !isTesSuccess(ret)) + if (view().rules().enabled(featureSponsor)) { - return ret; + if (auto const ret = checkReserve( + ctx_.getApplyViewContext(), + sleLowAccount, + preFeeBalance_, + lowSponsor, + {.ownerCountDelta = 1}, + j_, + tecINSUF_RESERVE_LINE); + lowSponsor && !isTesSuccess(ret)) + { + return ret; + } } // Set reserve for low account. @@ -567,17 +570,20 @@ TrustSet::doApply() // should be checked PreFunded Sponsor before increaseOwnerCount() // For PreFunded sponsors, we need to check if there are sufficient reserves before // calling increaseOwnerCount(). - if (auto const ret = checkReserve( - ctx_.getApplyViewContext(), - sleHighAccount, - preFeeBalance_, - highSponsor, - {.ownerCountDelta = 1}, - j_, - tecINSUF_RESERVE_LINE); - highSponsor && !isTesSuccess(ret)) + if (view().rules().enabled(featureSponsor)) { - return ret; + if (auto const ret = checkReserve( + ctx_.getApplyViewContext(), + sleHighAccount, + preFeeBalance_, + highSponsor, + {.ownerCountDelta = 1}, + j_, + tecINSUF_RESERVE_LINE); + highSponsor && !isTesSuccess(ret)) + { + return ret; + } } // Set reserve for high account. diff --git a/src/test/jtx/owners.h b/src/test/jtx/owners.h index a54391f8a3..3f64601244 100644 --- a/src/test/jtx/owners.h +++ b/src/test/jtx/owners.h @@ -64,7 +64,8 @@ public: operator()(Env& env) const; }; -/** Match the number of items in the account's owner directory */ +/** Match the account's SponsoredOwnerCount field: the number of owned + objects whose reserve is sponsored by another account. */ class SponsoredOwners { private: @@ -81,7 +82,8 @@ public: operator()(Env& env) const; }; -/** Match the number of items in the account's owner directory */ +/** Match the account's SponsoringOwnerCount field: the number of objects + (owned by other accounts) whose reserve this account sponsors. */ class SponsoringOwners { private: @@ -98,7 +100,8 @@ public: operator()(Env& env) const; }; -/** Match the number of items in the account's owner directory */ +/** Match the account's SponsoringAccountCount field: the number of accounts + whose base reserve this account sponsors. */ class SponsoringAccountCount { private: