mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-23 15:10:34 +00:00
Merge branch 'xrplf/sponsor' of https://github.com/XRPLF/rippled into mvadari/sponsor/apply-view-context
This commit is contained in:
@@ -21,46 +21,92 @@ namespace xrpl {
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen(ReadView const& view, AccountID const& issuer);
|
||||
|
||||
// Calculate liquid XRP balance for an account.
|
||||
// This function may be used to calculate the amount of XRP that
|
||||
// the holder is able to freely spend. It subtracts reserve requirements.
|
||||
//
|
||||
// ownerCountAdj adjusts the owner count in case the caller calculates
|
||||
// before ledger entries are added or removed. Positive to add, negative
|
||||
// to subtract.
|
||||
//
|
||||
// @param ownerCountAdj positive to add to count, negative to reduce count.
|
||||
/** Calculate liquid XRP balance for an account.
|
||||
*
|
||||
* This function may be used to calculate the amount of XRP that
|
||||
* the holder is able to freely spend. It subtracts reserve requirements.
|
||||
*
|
||||
* ownerCountAdj adjusts the owner count in case the caller calculates
|
||||
* before ledger entries are added or removed. Positive to add, negative
|
||||
* to subtract.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param id The account ID to check
|
||||
* @param ownerCountAdj Positive to add to count, negative to reduce count
|
||||
* @param j Journal for logging
|
||||
* @return The liquid XRP amount available to the account
|
||||
*/
|
||||
[[nodiscard]] XRPAmount
|
||||
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
|
||||
|
||||
/** Returns the account reserve, in drops.
|
||||
Actual owner count can be adjusted by delta in ownerCountAdj
|
||||
The reserve is calculated as
|
||||
(ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
||||
increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
||||
*/
|
||||
*
|
||||
* Actual owner count can be adjusted by delta in ownerCountAdj
|
||||
* Actual reserve count can be adjusted by delta in accountCountAdj
|
||||
* The reserve is calculated as:
|
||||
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
||||
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param sle The ledger entry for the account
|
||||
* @param j Journal for logging
|
||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||
* @param accountCountAdj Adjustment to the account count (default: 0)
|
||||
* @return The account reserve amount in drops
|
||||
*/
|
||||
[[nodiscard]] XRPAmount
|
||||
accountReserve(
|
||||
ReadView const& view,
|
||||
SLE::const_ref sle,
|
||||
beast::Journal j,
|
||||
std::int32_t ownerCountAdj = 0,
|
||||
std::int32_t reserveCountAdj = 0);
|
||||
std::int32_t accountCountAdj = 0);
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of SLE.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param id The account ID
|
||||
* @param j Journal for logging
|
||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||
* @param accountCountAdj Adjustment to the account count (default: 0)
|
||||
* @return The account reserve amount in drops
|
||||
*/
|
||||
[[nodiscard]] inline XRPAmount
|
||||
accountReserve(
|
||||
ReadView const& view,
|
||||
AccountID const& id,
|
||||
beast::Journal j,
|
||||
std::int32_t ownerCountAdj = 0,
|
||||
std::int32_t reserveCountAdj = 0)
|
||||
std::int32_t accountCountAdj = 0)
|
||||
{
|
||||
return accountReserve(view, view.read(keylet::account(id)), j, ownerCountAdj, reserveCountAdj);
|
||||
return accountReserve(view, view.read(keylet::account(id)), j, ownerCountAdj, accountCountAdj);
|
||||
}
|
||||
|
||||
/** @brief Return the hypothetical reserve required by an account with the provided counters.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param ownerCount Number of objects for which the account will be responsible.
|
||||
* @param accountCount Number of accounts for which the account will be responsible.
|
||||
* Defaults to 1, as normally every account is responsible for its own reserve.
|
||||
* Can be 0 if the account is sponsored.
|
||||
* Can be greater than 1 if the account is sponsoring other accounts.
|
||||
* @return The hypothetical reserve amount
|
||||
*/
|
||||
XRPAmount
|
||||
baseAccountReserve(ReadView const& view, std::int32_t ownerCount);
|
||||
baseAccountReserve(ReadView const& view, std::int32_t ownerCount, std::int32_t accountCount = 1);
|
||||
|
||||
/** Check if an account has insufficient reserve.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param tx The transaction being processed
|
||||
* @param accSle The account's ledger entry
|
||||
* @param accBalance The account's balance
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param ownerCountAdj Adjustment to the owner count
|
||||
* @param accountCountAdj Adjustment to the account count (default: 0)
|
||||
* @param j Journal for logging (default: null sink)
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkInsufficientReserve(
|
||||
ReadView const& view,
|
||||
@@ -68,60 +114,97 @@ checkInsufficientReserve(
|
||||
SLE::const_ref accSle,
|
||||
STAmount const& accBalance,
|
||||
SLE::const_ref sponsorSle,
|
||||
std::int32_t ownerCountDelta,
|
||||
std::int32_t reserveCountDelta = 0,
|
||||
std::int32_t ownerCountAdj,
|
||||
std::int32_t accountCountAdj = 0,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
/** Return number of the objects which reserve is covered by the account(sle) (so called "owner
|
||||
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
|
||||
*
|
||||
* @param sle The account's ledger entry
|
||||
* @param j Journal for logging
|
||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||
* @return The adjusted owner count
|
||||
*/
|
||||
std::uint32_t
|
||||
ownerCount(
|
||||
ReadView const& view,
|
||||
SLE::const_ref sle,
|
||||
beast::Journal j,
|
||||
std::int32_t ownerCountAdj = 0);
|
||||
ownerCount(SLE::const_ref sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
|
||||
|
||||
/** Adjust the owner count up or down. */
|
||||
/** Adjust the owner counters of the account up or down. If sponsor provided adjust its counters
|
||||
* too.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param accountCountAdj Adjustment amount for the account count
|
||||
* @param j Journal for logging (default: null sink)
|
||||
*/
|
||||
void
|
||||
adjustOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::int32_t amount,
|
||||
std::int32_t accountCountAdj,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of SLE references.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param account The account ID
|
||||
* @param sponsor The optional sponsor account ID
|
||||
* @param accountCountAdj Adjustment amount for the account count
|
||||
* @param j Journal for logging (default: null sink)
|
||||
*/
|
||||
inline void
|
||||
adjustOwnerCount(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
std::optional<AccountID> const& sponsor,
|
||||
std::int32_t amount,
|
||||
std::int32_t accountCountAdj,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
{
|
||||
adjustOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(account)),
|
||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
||||
amount,
|
||||
accountCountAdj,
|
||||
j);
|
||||
}
|
||||
|
||||
/** Adjust the owner counters of the account up or down. If object has sponsor adjust its counters
|
||||
* too. Used primarily just before deleting the object.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param objectSle The object's ledger entry
|
||||
* @param accountCountAdj Adjustment amount for the account count
|
||||
* @param j Journal for logging (default: null sink)
|
||||
*/
|
||||
void
|
||||
adjustOwnerCountObj(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref objectSle,
|
||||
std::int32_t amount,
|
||||
std::int32_t accountCountAdj,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of account SLE reference.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param account The account ID
|
||||
* @param objectSle The object's ledger entry
|
||||
* @param accountCountAdj Adjustment amount for the account count
|
||||
* @param j Journal for logging (default: null sink)
|
||||
*/
|
||||
inline void
|
||||
adjustOwnerCountObj(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
SLE::ref objectSle,
|
||||
std::int32_t amount,
|
||||
std::int32_t accountCountAdj,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
{
|
||||
SLE::ref accountSle = view.peek(keylet::account(account));
|
||||
adjustOwnerCountObj(view, accountSle, objectSle, amount, j);
|
||||
adjustOwnerCountObj(view, accountSle, objectSle, accountCountAdj, j);
|
||||
}
|
||||
|
||||
/** Returns IOU issuer transfer fee as Rate. Rate specifies
|
||||
@@ -142,25 +225,25 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey);
|
||||
/** Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account
|
||||
if set.
|
||||
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
[[nodiscard]] std::vector<SField const*> const&
|
||||
getPseudoAccountFields();
|
||||
|
||||
/** Returns true if and only if sleAcct is a pseudo-account or specific
|
||||
pseudo-accounts in pseudoFieldFilter.
|
||||
|
||||
Returns false if sleAcct is:
|
||||
- NOT a pseudo-account OR
|
||||
- NOT a ltACCOUNT_ROOT OR
|
||||
- null pointer
|
||||
*/
|
||||
/** Convenience overload that reads the account from the view. */
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccount(SLE::const_ref sleAcct, std::set<SField const*> const& pseudoFieldFilter = {});
|
||||
|
||||
/** Convenience overload that reads the account from the view. */
|
||||
/** Convenience overload that reads the account from the view.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param accountId The account ID to check
|
||||
* @param pseudoFieldFilter Optional set of specific pseudo-account fields to filter (default:
|
||||
* empty)
|
||||
* @return true if the account is a pseudo-account (or matches the filter), false otherwise
|
||||
*/
|
||||
[[nodiscard]] inline bool
|
||||
isPseudoAccount(
|
||||
ReadView const& view,
|
||||
@@ -183,8 +266,8 @@ createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const
|
||||
|
||||
/** Checks the destination and tag.
|
||||
|
||||
- Checks that the SLE is not null.
|
||||
- If the SLE requires a destination tag, checks that there is a tag.
|
||||
- Checks that the SLE is not null.
|
||||
- If the SLE requires a destination tag, checks that there is a tag.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag);
|
||||
|
||||
@@ -51,141 +51,103 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer)
|
||||
// Returns adjusted owner count.
|
||||
static std::uint32_t
|
||||
confineOwnerCount(
|
||||
std::uint32_t current,
|
||||
std::int32_t adjustment,
|
||||
std::uint32_t currentOwnerCount,
|
||||
std::int32_t ownerCountAdj,
|
||||
std::optional<AccountID> const& id = std::nullopt,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
{
|
||||
std::uint32_t adjusted{current + adjustment};
|
||||
if (adjustment > 0)
|
||||
std::uint32_t totalOwnerCount{currentOwnerCount + ownerCountAdj};
|
||||
if (ownerCountAdj > 0)
|
||||
{
|
||||
// Overflow is well defined on unsigned
|
||||
if (adjusted < current)
|
||||
if (totalOwnerCount < currentOwnerCount)
|
||||
{
|
||||
if (id)
|
||||
{
|
||||
JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!";
|
||||
}
|
||||
adjusted = std::numeric_limits<std::uint32_t>::max();
|
||||
totalOwnerCount = std::numeric_limits<std::uint32_t>::max();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Underflow is well defined on unsigned
|
||||
if (adjusted > current)
|
||||
if (totalOwnerCount > currentOwnerCount)
|
||||
{
|
||||
if (id)
|
||||
{
|
||||
JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!";
|
||||
}
|
||||
adjusted = 0;
|
||||
totalOwnerCount = 0;
|
||||
XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set");
|
||||
}
|
||||
}
|
||||
return adjusted;
|
||||
return totalOwnerCount;
|
||||
}
|
||||
|
||||
// Return number of the accounts which reserve is covered by current account (so called "reserve
|
||||
// count")
|
||||
static std::uint32_t
|
||||
ownerCountHlp(
|
||||
ReadView const& view,
|
||||
SLE::const_ref sle,
|
||||
std::int32_t adjustment,
|
||||
bool reportConfine,
|
||||
beast::Journal j)
|
||||
accountCountImpl(SLE::const_ref sle, std::int32_t accountCountAdj, beast::Journal j)
|
||||
{
|
||||
AccountID const id = sle->getAccountID(sfAccount);
|
||||
std::uint32_t const savedCount = sle->at(sfOwnerCount);
|
||||
std::uint32_t const hookedCount = view.ownerCountHook(id, savedCount);
|
||||
bool const isSponsored = sle->isFieldPresent(sfSponsor);
|
||||
std::int64_t const sponsoringAccountCount = sle->getFieldU32(sfSponsoringAccountCount);
|
||||
std::int64_t const currentAccountCount = (isSponsored ? 0 : 1) + sponsoringAccountCount;
|
||||
|
||||
std::uint32_t const sponsoredCount = sle->at(sfSponsoredOwnerCount);
|
||||
std::uint32_t const sponsoringCount = sle->at(sfSponsoringOwnerCount);
|
||||
|
||||
if (hookedCount < sponsoredCount)
|
||||
std::int64_t totalAccountCount{currentAccountCount + accountCountAdj};
|
||||
if (totalAccountCount > std::numeric_limits<std::uint32_t>::max())
|
||||
{
|
||||
Throw<std::logic_error>(
|
||||
"xrpl::ownerCountHlp : OwnerCount must be greater than or equal to "
|
||||
"SponsoredOwnerCount");
|
||||
JLOG(j.error()) << "Reserve count exceeds max!";
|
||||
totalAccountCount = std::numeric_limits<std::uint32_t>::max();
|
||||
}
|
||||
else if (totalAccountCount < 0)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::accountCountImpl : Reserve count set below 0");
|
||||
JLOG(j.fatal()) << "Reserve count set below 0";
|
||||
totalAccountCount = 0;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return totalAccountCount;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
ownerCount(SLE::const_ref sle, beast::Journal j, std::int32_t ownerCountAdj)
|
||||
{
|
||||
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::ownerCount : sle is account root");
|
||||
|
||||
AccountID const id = sle->getAccountID(sfAccount);
|
||||
std::uint32_t const currentOwnerCount = sle->at(sfOwnerCount);
|
||||
std::uint32_t const sponsoredOwnerCount = sle->at(sfSponsoredOwnerCount);
|
||||
std::uint32_t const sponsoringOwnerCount = sle->at(sfSponsoringOwnerCount);
|
||||
|
||||
XRPL_ASSERT(
|
||||
currentOwnerCount >= sponsoredOwnerCount,
|
||||
"xrpl::ownerCount : OwnerCount must be greater than or equal to "
|
||||
"SponsoredOwnerCount");
|
||||
|
||||
std::int64_t deltaCount =
|
||||
static_cast<std::int64_t>(adjustment) - sponsoredCount + sponsoringCount;
|
||||
static_cast<std::int64_t>(ownerCountAdj) - sponsoredOwnerCount + sponsoringOwnerCount;
|
||||
|
||||
if (deltaCount > std::numeric_limits<std::int32_t>::max())
|
||||
{
|
||||
deltaCount = std::numeric_limits<std::int32_t>::max();
|
||||
JLOG(j.fatal()) << "Account " << id << " delta count exceeds max, "
|
||||
<< "adjustment: " << adjustment << ", sponsoredCount: " << sponsoredCount
|
||||
<< ", sponsoringOwnerCount: " << sponsoringCount;
|
||||
<< "adjustment: " << ownerCountAdj
|
||||
<< ", sponsoredCount: " << sponsoredOwnerCount
|
||||
<< ", sponsoringOwnerCount: " << sponsoringOwnerCount;
|
||||
}
|
||||
else if (deltaCount < std::numeric_limits<std::int32_t>::min())
|
||||
{
|
||||
deltaCount = std::numeric_limits<std::int32_t>::min();
|
||||
JLOG(j.fatal()) << "Account " << id << " delta count exceeds min, "
|
||||
<< "adjustment: " << adjustment << ", sponsoredCount: " << sponsoredCount
|
||||
<< ", sponsoringCount: " << sponsoringCount;
|
||||
JLOG(j.fatal()) << "Account " << id << " delta count is below min, "
|
||||
<< "adjustment: " << ownerCountAdj
|
||||
<< ", sponsoredCount: " << sponsoredOwnerCount
|
||||
<< ", sponsoringCount: " << sponsoringOwnerCount;
|
||||
}
|
||||
|
||||
std::uint32_t const confinedCount = reportConfine
|
||||
? confineOwnerCount(hookedCount, deltaCount, id, j)
|
||||
: confineOwnerCount(hookedCount, deltaCount);
|
||||
|
||||
return confinedCount;
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
reserveCountHlp(SLE::const_ref sle, std::int32_t adjustment, beast::Journal j)
|
||||
{
|
||||
bool const isSponsored = sle->isFieldPresent(sfSponsor);
|
||||
std::uint32_t const sponsoringCount = sle->getFieldU32(sfSponsoringAccountCount);
|
||||
std::uint32_t const reserveCount = (isSponsored ? 0 : 1) + sponsoringCount;
|
||||
|
||||
std::uint32_t adjusted{reserveCount + adjustment};
|
||||
if (adjustment > 0)
|
||||
{
|
||||
// Overflow is well defined on unsigned
|
||||
if (adjusted < reserveCount)
|
||||
{
|
||||
JLOG(j.fatal()) << "Reserve count exceeds max!";
|
||||
adjusted = std::numeric_limits<std::uint32_t>::max();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Underflow is well defined on unsigned
|
||||
if (adjusted > reserveCount)
|
||||
{
|
||||
JLOG(j.fatal()) << "Reserve count set below 0!";
|
||||
adjusted = 0;
|
||||
}
|
||||
}
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
static inline XRPAmount
|
||||
baseReserveHlp(ReadView const& view, std::uint32_t ownerCount, std::uint32_t reserveCount)
|
||||
{
|
||||
auto const& fees = view.fees();
|
||||
return (fees.reserve * reserveCount) + (fees.increment * ownerCount);
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
reserveHlp(
|
||||
ReadView const& view,
|
||||
SLE::const_ref sle,
|
||||
std::uint32_t ownerCount,
|
||||
std::uint32_t reserveCount)
|
||||
{
|
||||
// Pseudo-accounts have no reserve requirement
|
||||
if (isPseudoAccount(sle))
|
||||
return XRPAmount(0);
|
||||
|
||||
auto const reserve = baseReserveHlp(view, ownerCount, reserveCount);
|
||||
return reserve;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
ownerCount(ReadView const& view, SLE::const_ref sle, beast::Journal j, std::int32_t adjustment)
|
||||
{
|
||||
return ownerCountHlp(view, sle, adjustment, true, j);
|
||||
return confineOwnerCount(currentOwnerCount, deltaCount);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
@@ -195,9 +157,15 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
|
||||
if (sle == nullptr)
|
||||
return beast::kZero;
|
||||
|
||||
std::uint32_t const ownerCount = ownerCountHlp(view, sle, ownerCountAdj, false, j);
|
||||
std::uint32_t const reserveCount = reserveCountHlp(sle, 0, j);
|
||||
auto const reserve = reserveHlp(view, sle, ownerCount, reserveCount);
|
||||
// Return balance minus reserve
|
||||
std::uint32_t const currentOwnerCount =
|
||||
confineOwnerCount(view.ownerCountHook(id, ownerCount(sle, j)), ownerCountAdj);
|
||||
std::uint32_t const currentAccountCount = accountCountImpl(sle, 0, j);
|
||||
|
||||
// Pseudo-accounts have no reserve requirement
|
||||
auto const reserve = isPseudoAccount(sle)
|
||||
? XRPAmount{0}
|
||||
: baseAccountReserve(view, currentOwnerCount, currentAccountCount);
|
||||
|
||||
auto const fullBalance = sle->getFieldAmount(sfBalance);
|
||||
|
||||
@@ -209,7 +177,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
|
||||
<< " amount=" << amount.getFullText()
|
||||
<< " fullBalance=" << fullBalance.getFullText()
|
||||
<< " balance=" << balance.getFullText() << " reserve=" << reserve
|
||||
<< " ownerCount=" << ownerCount << " ownerCountAdj=" << ownerCountAdj;
|
||||
<< " ownerCount=" << currentOwnerCount << " ownerCountAdj=" << ownerCountAdj;
|
||||
|
||||
return amount.xrp();
|
||||
}
|
||||
@@ -226,20 +194,21 @@ transferRate(ReadView const& view, AccountID const& issuer)
|
||||
}
|
||||
|
||||
static void
|
||||
adjustOwnerCountHlp(
|
||||
adjustOwnerCountImpl(
|
||||
ApplyView& view,
|
||||
SLE::ref sle,
|
||||
SF_UINT32 const& sfield,
|
||||
AccountID const& accID,
|
||||
std::int32_t adjustment,
|
||||
std::int32_t ownerCountAdj,
|
||||
beast::Journal j,
|
||||
bool callHook = true)
|
||||
{
|
||||
std::uint32_t const current = sle->at(sfield);
|
||||
std::uint32_t const adjusted = confineOwnerCount(current, adjustment, accID, j);
|
||||
std::uint32_t const currentOwnerCount = sle->at(sfield);
|
||||
std::uint32_t const totalOwnerCount =
|
||||
confineOwnerCount(currentOwnerCount, ownerCountAdj, accID, j);
|
||||
if (callHook)
|
||||
view.adjustOwnerCountHook(accID, current, adjusted);
|
||||
sle->at(sfield) = adjusted;
|
||||
view.adjustOwnerCountHook(accID, currentOwnerCount, totalOwnerCount);
|
||||
sle->at(sfield) = totalOwnerCount;
|
||||
view.update(sle);
|
||||
}
|
||||
|
||||
@@ -248,7 +217,7 @@ adjustOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::int32_t adjustment,
|
||||
std::int32_t ownerCountAdj,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (!accountSle)
|
||||
@@ -260,8 +229,8 @@ adjustOwnerCount(
|
||||
if (!validType)
|
||||
Throw<std::logic_error>("xrpl::adjustOwnerCount : valid account sle type");
|
||||
|
||||
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCount : nonzero adjustment input");
|
||||
if (adjustment == 0)
|
||||
XRPL_ASSERT(ownerCountAdj, "xrpl::adjustOwnerCount : nonzero ownerCountAdj input");
|
||||
if (ownerCountAdj == 0)
|
||||
return;
|
||||
|
||||
auto const accountID = accountSle->getAccountID(sfAccount);
|
||||
@@ -271,20 +240,21 @@ adjustOwnerCount(
|
||||
Throw<std::logic_error>("xrpl::adjustOwnerCount : valid sponsor sle type");
|
||||
auto const sponsorID = sponsorSle->getAccountID(sfAccount);
|
||||
|
||||
adjustOwnerCountHlp(view, accountSle, sfSponsoredOwnerCount, accountID, adjustment, j);
|
||||
adjustOwnerCountHlp(view, sponsorSle, sfSponsoringOwnerCount, sponsorID, adjustment, j);
|
||||
adjustOwnerCountImpl(view, accountSle, sfSponsoredOwnerCount, accountID, ownerCountAdj, j);
|
||||
adjustOwnerCountImpl(view, sponsorSle, sfSponsoringOwnerCount, sponsorID, ownerCountAdj, j);
|
||||
|
||||
auto sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
|
||||
if (sponsorshipSle && adjustment > 0)
|
||||
if (sponsorshipSle && ownerCountAdj > 0)
|
||||
{
|
||||
// update the pre-funded RemainingOwnerCount on Sponsorship ledger object
|
||||
// Remaining owner count moves opposite to adjustment:
|
||||
// +adjustment => consume reserve (-),
|
||||
adjustOwnerCountHlp(
|
||||
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j, false);
|
||||
// Only decrease the pre-funded ReserveCount on Sponsorship if we assign new objects.
|
||||
// Removing/reassigning ownership of the object doesn't increase RemainingOwnerCount
|
||||
// back. Don't call hook because this counter is not something that require reserve
|
||||
// (like other sf...OwnerCounts do).
|
||||
adjustOwnerCountImpl(
|
||||
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -ownerCountAdj, j, false);
|
||||
}
|
||||
}
|
||||
adjustOwnerCountHlp(view, accountSle, sfOwnerCount, accountID, adjustment, j);
|
||||
adjustOwnerCountImpl(view, accountSle, sfOwnerCount, accountID, ownerCountAdj, j);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -292,7 +262,7 @@ adjustOwnerCountObj(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref objectSle,
|
||||
std::int32_t amount,
|
||||
std::int32_t accountCountAdj,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (!objectSle)
|
||||
@@ -301,7 +271,7 @@ adjustOwnerCountObj(
|
||||
Throw<std::logic_error>("xrpl::adjustOwnerCount : valid object sle type");
|
||||
|
||||
SLE::ref sponsorSle = getLedgerEntryReserveSponsor(view, objectSle);
|
||||
adjustOwnerCount(view, accountSle, sponsorSle, amount, j);
|
||||
adjustOwnerCount(view, accountSle, sponsorSle, accountCountAdj, j);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
@@ -310,24 +280,24 @@ accountReserve(
|
||||
SLE::const_ref sle,
|
||||
beast::Journal j,
|
||||
std::int32_t ownerCountAdj,
|
||||
std::int32_t reserveCountAdj)
|
||||
std::int32_t accountCountAdj)
|
||||
{
|
||||
if (!sle)
|
||||
Throw<std::runtime_error>("xrpl::accountReserve : valid sle");
|
||||
if (sle->getType() != ltACCOUNT_ROOT)
|
||||
Throw<std::logic_error>("xrpl::accountReserve : valid sle type");
|
||||
|
||||
std::uint32_t const ownerCount = ownerCountHlp(view, sle, ownerCountAdj, true, j);
|
||||
std::uint32_t const reserveCount = reserveCountHlp(sle, reserveCountAdj, j);
|
||||
std::uint32_t const currentOwnerCount = ownerCount(sle, j, ownerCountAdj);
|
||||
std::uint32_t const currentAccountCount = accountCountImpl(sle, accountCountAdj, j);
|
||||
|
||||
return reserveHlp(view, sle, ownerCount, reserveCount);
|
||||
return baseAccountReserve(view, currentOwnerCount, currentAccountCount);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
baseAccountReserve(ReadView const& view, std::int32_t ownerCount)
|
||||
baseAccountReserve(ReadView const& view, std::int32_t ownerCount, std::int32_t accountCount)
|
||||
{
|
||||
auto const reserve = baseReserveHlp(view, ownerCount, 1);
|
||||
return reserve;
|
||||
auto const& fees = view.fees();
|
||||
return (fees.reserve * accountCount) + (fees.increment * ownerCount);
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -337,8 +307,8 @@ checkInsufficientReserve(
|
||||
SLE::const_ref accSle,
|
||||
STAmount const& accBalance,
|
||||
SLE::const_ref sponsorSle,
|
||||
std::int32_t ownerCountDelta,
|
||||
std::int32_t reserveCountDelta,
|
||||
std::int32_t ownerCountAdj,
|
||||
std::int32_t accountCountAdj,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (sponsorSle)
|
||||
@@ -356,21 +326,20 @@ checkInsufficientReserve(
|
||||
if (sle)
|
||||
{
|
||||
auto const ownerCountAllowed = sle->getFieldU32(sfRemainingOwnerCount);
|
||||
if (ownerCountAllowed < ownerCountDelta)
|
||||
if (ownerCountAllowed < ownerCountAdj)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
auto const sponsorBalance = sponsorSle->getFieldAmount(sfBalance);
|
||||
STAmount const sponsorReserve =
|
||||
accountReserve(view, sponsorSle, j, ownerCountDelta, reserveCountDelta);
|
||||
accountReserve(view, sponsorSle, j, ownerCountAdj, accountCountAdj);
|
||||
|
||||
if (sponsorBalance < sponsorReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
STAmount const reserve =
|
||||
accountReserve(view, accSle, j, ownerCountDelta, reserveCountDelta);
|
||||
STAmount const reserve = accountReserve(view, accSle, j, ownerCountAdj, accountCountAdj);
|
||||
if (accBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ authorizeMPToken(
|
||||
// The "free-tier" shortcut (ownerCount < 2) does not apply once a sponsor is on
|
||||
// the tx — the sponsor must always cover the reserve (via balance or prefunded
|
||||
// budget), so this check always runs for sponsored transactions.
|
||||
if (*sponsorSle || ownerCount(view, sleAcct, journal) >= 2)
|
||||
if (*sponsorSle || ownerCount(sleAcct, journal) >= 2)
|
||||
{
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view, ctx.tx, sleAcct, priorBalance, *sponsorSle, 1, 0, journal);
|
||||
|
||||
@@ -630,15 +630,14 @@ AMMWithdraw::withdraw(
|
||||
if (!sleAccount)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
STAmount const balance = (*sleAccount)[sfBalance];
|
||||
std::uint32_t const currentOwnerCount = ownerCount(view, sleAccount, journal);
|
||||
|
||||
auto const balance = (*sleAccount)[sfBalance]->xrp();
|
||||
std::uint32_t const currentOwnerCount = ownerCount(sleAccount, journal);
|
||||
// See also TrustSet::doApply() and MPTokenAuthorize::authorize()
|
||||
XRPAmount const reserve(
|
||||
(currentOwnerCount < 2) ? XRPAmount(beast::kZero)
|
||||
: accountReserve(view, sleAccount, journal, 1));
|
||||
|
||||
auto const balanceAdj = isIssue ? std::max(priorBalance, balance.xrp()) : priorBalance;
|
||||
auto const balanceAdj = isIssue ? std::max(priorBalance, balance) : priorBalance;
|
||||
if (balanceAdj < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ TrustSet::doApply()
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
std::uint32_t const uOwnerCount = ownerCount(view(), *sponsorSle ? *sponsorSle : sle, j_);
|
||||
std::uint32_t const uOwnerCount = ownerCount(*sponsorSle ? *sponsorSle : sle, j_);
|
||||
|
||||
// The "free-tier" shortcut (ownerCount < 2) only applies when there is no sponsor.
|
||||
// With any sponsor on the tx, the sponsor must cover the reserve (via balance or
|
||||
|
||||
Reference in New Issue
Block a user