From 4afd95e4b385897c47cd363afece1d9bfbf7a8bb Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 2 Jul 2026 17:30:50 -0400 Subject: [PATCH] migrate lending usage of owner count --- include/xrpl/ledger/helpers/LendingHelpers.h | 15 ++++++++++ .../ledger/helpers/AccountRootHelpers.cpp | 4 +-- src/libxrpl/ledger/helpers/LendingHelpers.cpp | 28 +++++++++++++++++++ .../tx/transactors/lending/LoanDelete.cpp | 2 +- .../tx/transactors/lending/LoanSet.cpp | 2 +- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/include/xrpl/ledger/helpers/LendingHelpers.h b/include/xrpl/ledger/helpers/LendingHelpers.h index c21e5bf0ce..4c46fbb1d8 100644 --- a/include/xrpl/ledger/helpers/LendingHelpers.h +++ b/include/xrpl/ledger/helpers/LendingHelpers.h @@ -58,6 +58,21 @@ canApplyToBrokerCover( bool checkLendingProtocolDependencies(Rules const& rules, STTx const& tx); +/** Adjust a LoanBroker's own sfOwnerCount. + * + * A LoanBroker's OwnerCount tracks the number of outstanding loans it holds, + * and is distinct from the broker's pseudo-account's owner count. Unlike an + * account's OwnerCount it carries no reserve and cannot be sponsored, so it is + * adjusted directly here rather than through ReserveContext / increaseOwnerCount. + * + * @param view The apply view for making changes + * @param brokerSle The LoanBroker ledger entry + * @param amount Signed amount to add to the loan count (nonzero) + * @param j Journal for logging + */ +void +adjustOwnerCount(ApplyView& view, SLE::ref brokerSle, std::int32_t amount, beast::Journal j); + static constexpr std::uint32_t kSecondsInYear = 365 * 24 * 60 * 60; Number diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index 8ecbd1d8a2..5823f575b5 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -224,9 +224,7 @@ adjustOwnerCountSigned( if (!accountSle) return; // LCOV_EXCL_LINE - auto const sleType = accountSle->getType(); - bool const validType = sponsorSle ? sleType == ltACCOUNT_ROOT - : sleType == ltLOAN_BROKER || sleType == ltACCOUNT_ROOT; + bool const validType = accountSle->getType() == ltACCOUNT_ROOT; XRPL_ASSERT(validType, "xrpl::adjustOwnerCountSigned : valid account sle type"); if (!validType) return; // LCOV_EXCL_LINE diff --git a/src/libxrpl/ledger/helpers/LendingHelpers.cpp b/src/libxrpl/ledger/helpers/LendingHelpers.cpp index f7ec8a8bc3..f1cbe4ef70 100644 --- a/src/libxrpl/ledger/helpers/LendingHelpers.cpp +++ b/src/libxrpl/ledger/helpers/LendingHelpers.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -61,6 +63,32 @@ canApplyToBrokerCover( return tesSUCCESS; } +void +adjustOwnerCount(ApplyView& view, SLE::ref brokerSle, std::int32_t amount, beast::Journal j) +{ + XRPL_ASSERT( + brokerSle && brokerSle->getType() == ltLOAN_BROKER, + "xrpl::adjustOwnerCount : valid LoanBroker sle"); + if (!brokerSle) + return; // LCOV_EXCL_LINE + XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input"); + + // A LoanBroker's OwnerCount counts its outstanding loans; it carries no + // reserve, so clamp against underflow/overflow (as an account owner count + // would) but skip all reserve/sponsor accounting. + std::uint32_t const current = brokerSle->at(sfOwnerCount); + std::uint32_t adjusted = current + amount; + if (amount > 0 && adjusted < current) + adjusted = std::numeric_limits::max(); // LCOV_EXCL_LINE + else if (amount < 0 && adjusted > current) + adjusted = 0; // LCOV_EXCL_LINE + + AccountID const id = brokerSle->getAccountID(sfAccount); + view.adjustOwnerCountHook(id, current, adjusted); + brokerSle->at(sfOwnerCount) = adjusted; + view.update(brokerSle); +} + bool checkLendingProtocolDependencies(Rules const& rules, STTx const& tx) { diff --git a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp index 699bb1c43f..07952de807 100644 --- a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp @@ -110,7 +110,7 @@ LoanDelete::doApply() // Decrement the LoanBroker's owner count. // The broker's owner count is solely for the number of outstanding loans, // and is distinct from the broker's pseudo-account's owner count - decreaseOwnerCount(view, ReserveContext::makeFromAccount(view, brokerSle, nullptr), 1, j_); + adjustOwnerCount(view, brokerSle, -1, j_); // If there are no loans left, then any remaining debt must be forgiven, // because there is no other way to pay it back. diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index 7f47745635..dba4a1a5bf 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -647,7 +647,7 @@ LoanSet::doApply() adjustImpreciseNumber(brokerSle->at(sfDebtTotal), newDebtDelta, vaultAsset, vaultScale); // The broker's owner count is solely for the number of outstanding loans, // and is distinct from the broker's pseudo-account's owner count - increaseOwnerCount(view, ReserveContext::makeFromAccount(view, brokerSle, nullptr), 1, j_); + adjustOwnerCount(view, brokerSle, 1, j_); loanSequenceProxy += 1; // The sequence should be extremely unlikely to roll over, but fail if it // does