diff --git a/include/xrpl/ledger/helpers/AccountRootHelpers.h b/include/xrpl/ledger/helpers/AccountRootHelpers.h index a988468f2f..bcd7317b68 100644 --- a/include/xrpl/ledger/helpers/AccountRootHelpers.h +++ b/include/xrpl/ledger/helpers/AccountRootHelpers.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -165,6 +167,25 @@ using WAccountRoot = AccountRoot; extern template class AccountRoot; extern template class AccountRoot; +namespace detail { + +/** Confine an owner count adjustment to the valid range. + + If adjustment would underflow or overflow the owner count, clamp it to the + nearest valid value. If id is supplied, log fatal diagnostics for invalid + adjustments. + + @return The adjusted owner count. +*/ +[[nodiscard]] std::uint32_t +confineOwnerCount( + std::uint32_t current, + std::int32_t adjustment, + std::optional const& id = std::nullopt, + beast::Journal j = beast::Journal{beast::Journal::getNullSink()}); + +} // namespace detail + /** Generate a pseudo-account address from a pseudo owner key. @param pseudoOwnerKey The key to generate the address from @return The generated account ID diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index 1030bac5f8..83481a8d12 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -40,18 +39,12 @@ AccountRoot::isGlobalFrozen() const return this->sle_->isFlag(lsfGlobalFreeze); } -// An owner count cannot be negative. If adjustment would cause a negative -// owner count, clamp the owner count at 0. Similarly for overflow. This -// adjustment allows the ownerCount to be adjusted up or down in multiple steps. -// If id != std::nullopt, then do error reporting. -// -// Returns adjusted owner count. -static std::uint32_t -confineOwnerCount( +std::uint32_t +detail::confineOwnerCount( std::uint32_t current, std::int32_t adjustment, - std::optional const& id = std::nullopt, - beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) + std::optional const& id, + beast::Journal j) { std::uint32_t adjusted{current + adjustment}; if (adjustment > 0) @@ -76,7 +69,7 @@ confineOwnerCount( JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!"; } adjusted = 0; - XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set"); + XRPL_ASSERT(!id, "xrpl::detail::confineOwnerCount : id is not set"); } } return adjusted; @@ -90,7 +83,7 @@ AccountRoot::xrpLiquid(std::int32_t ownerCountAdj) const return beast::kZero; // Return balance minus reserve - std::uint32_t const ownerCount = confineOwnerCount( + std::uint32_t const ownerCount = detail::confineOwnerCount( this->readView().ownerCountHook(id_, this->sle_->getFieldU32(sfOwnerCount)), ownerCountAdj); // Pseudo-accounts have no reserve requirement @@ -131,7 +124,7 @@ AccountRoot::adjustOwnerCount(std::int32_t amount) XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input"); std::uint32_t const current{this->sle_->getFieldU32(sfOwnerCount)}; AccountID const id = (*this->sle_)[sfAccount]; - std::uint32_t const adjusted = confineOwnerCount(current, amount, id, this->j_); + std::uint32_t const adjusted = detail::confineOwnerCount(current, amount, id, this->j_); this->applyView().adjustOwnerCountHook(id_, current, adjusted); this->sle_->at(sfOwnerCount) = adjusted; this->update(); diff --git a/src/libxrpl/ledger/helpers/LendingHelpers.cpp b/src/libxrpl/ledger/helpers/LendingHelpers.cpp index 6976f2833a..8ccfd2f2e4 100644 --- a/src/libxrpl/ledger/helpers/LendingHelpers.cpp +++ b/src/libxrpl/ledger/helpers/LendingHelpers.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -26,9 +27,7 @@ #include #include #include -#include #include -#include #include #include @@ -2158,48 +2157,6 @@ loanMakePayment( return totalParts; } -// An owner count cannot be negative. If adjustment would cause a negative -// owner count, clamp the owner count at 0. Similarly for overflow. This -// adjustment allows the ownerCount to be adjusted up or down in multiple steps. -// If id != std::nullopt, then do error reporting. -// -// Returns adjusted owner count. -static std::uint32_t -confineOwnerCount( - std::uint32_t current, - std::int32_t adjustment, - std::optional const& id = std::nullopt, - beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) -{ - std::uint32_t adjusted{current + adjustment}; - if (adjustment > 0) - { - // Overflow is well defined on unsigned - if (adjusted < current) - { - if (id) - { - JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!"; - } - adjusted = std::numeric_limits::max(); - } - } - else - { - // Underflow is well defined on unsigned - if (adjusted > current) - { - if (id) - { - JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!"; - } - adjusted = 0; - XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set"); - } - } - return adjusted; -} - void adjustOwnerCount( std::shared_ptr const& sle, @@ -2215,7 +2172,7 @@ adjustOwnerCount( XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input"); std::uint32_t const current{sle->getFieldU32(sfOwnerCount)}; AccountID const id = (*sle)[sfAccount]; - std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j); + std::uint32_t const adjusted = detail::confineOwnerCount(current, amount, id, j); view.adjustOwnerCountHook(id, current, adjusted); sle->at(sfOwnerCount) = adjusted; view.update(sle);