mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-19 18:18:12 +00:00
Compare commits
6 Commits
develop
...
mvadari/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f06277ffe | ||
|
|
563b3a179e | ||
|
|
53984ccd50 | ||
|
|
e5010cb4f8 | ||
|
|
447a4f8723 | ||
|
|
10d64ef942 |
@@ -7,6 +7,12 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -28,6 +34,66 @@ public:
|
||||
: Base(keylet::sponsorship(sponsor, sponsee), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the resulting RemainingOwnerCount using signed 64-bit
|
||||
* arithmetic to avoid unsigned wraparound.
|
||||
*
|
||||
* A missing entry (object creation) or absent field counts as zero.
|
||||
* Callers handle the out-of-range results: a negative value is clamped to
|
||||
* zero (field absent) and overflow is rejected in preclaim.
|
||||
*
|
||||
* @param remainingOwnerCountDelta The requested change, if any
|
||||
* @return The current RemainingOwnerCount plus the delta
|
||||
*/
|
||||
[[nodiscard]] std::int64_t
|
||||
totalRemainingOwnerCount(std::optional<std::int32_t> const& remainingOwnerCountDelta) const
|
||||
{
|
||||
std::uint32_t const currentCount =
|
||||
this->exists() ? (**this)[~sfRemainingOwnerCount].value_or(0u) : 0u;
|
||||
return static_cast<std::int64_t>(currentCount) + remainingOwnerCountDelta.value_or(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if applying the deltas leaves the Sponsorship with a
|
||||
* budget: a positive FeeAmount or a positive RemainingOwnerCount.
|
||||
*
|
||||
* A missing entry (object creation) requires both deltas, when present,
|
||||
* to be positive.
|
||||
*
|
||||
* @param feeAmountDelta The requested FeeAmount change, if any
|
||||
* @param remainingOwnerCountDelta The requested RemainingOwnerCount change, if any
|
||||
* @return True if the resulting FeeAmount or RemainingOwnerCount would be
|
||||
* positive; false otherwise
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
hasBudget(
|
||||
std::optional<STAmount> const& feeAmountDelta,
|
||||
std::optional<std::int32_t> const& remainingOwnerCountDelta) const;
|
||||
|
||||
/**
|
||||
* Consumes the sponsor's pre-funded reserve budget: lowers
|
||||
* RemainingOwnerCount by delta and updates the entry.
|
||||
*
|
||||
* @param delta The number of owner reserves to consume
|
||||
* @return tesSUCCESS, or tefINTERNAL if the count is too low
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
decrementPrefundedReserveCount(std::uint32_t delta)
|
||||
requires Base::kIsWritable;
|
||||
|
||||
/**
|
||||
* Removes the Sponsorship from the sponsor's and sponsee's directories,
|
||||
* decrements the sponsor's owner count, returns any pre-funded FeeAmount
|
||||
* to the sponsor and erases the Sponsorship from the ledger.
|
||||
*
|
||||
* The sponsor and sponsee are read from sfOwner and sfSponsee.
|
||||
*
|
||||
* @return tesSUCCESS, or tecINTERNAL / tefBAD_LEDGER on failure
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
removeFromLedger()
|
||||
requires Base::kIsWritable;
|
||||
};
|
||||
|
||||
using SponsorshipEntryR = SponsorshipEntry<ReadView>;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
private:
|
||||
TER
|
||||
createSponsorship(
|
||||
Keylet const& sponsorshipKeylet,
|
||||
SponsorshipEntryW& sponsorship,
|
||||
AccountID const& sponsorID,
|
||||
AccountID const& sponseeID,
|
||||
SLE::Ref sponsorAccSle,
|
||||
|
||||
121
src/libxrpl/ledger/entries/SponsorshipEntry.cpp
Normal file
121
src/libxrpl/ledger/entries/SponsorshipEntry.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <typename ViewT>
|
||||
bool
|
||||
SponsorshipEntry<ViewT>::hasBudget(
|
||||
std::optional<STAmount> const& feeAmountDelta,
|
||||
std::optional<std::int32_t> const& remainingOwnerCountDelta) const
|
||||
{
|
||||
// sfFeeAmountDelta and sfRemainingOwnerCountDelta must be non-negative when creating a new
|
||||
// Sponsorship object.
|
||||
if (!this->exists())
|
||||
{
|
||||
if (feeAmountDelta.has_value() && *feeAmountDelta <= beast::kZero)
|
||||
return false;
|
||||
|
||||
if (remainingOwnerCountDelta.has_value() && *remainingOwnerCountDelta <= 0)
|
||||
return false;
|
||||
}
|
||||
// If the transaction omits a field, it keeps whatever the existing object holds,
|
||||
// so fall back to the current SLE value when the tx does not set it.
|
||||
STAmount const currentFee =
|
||||
this->exists() ? (**this)[~sfFeeAmount].value_or(STAmount{0}) : STAmount{0};
|
||||
STAmount const newFee = currentFee + feeAmountDelta.value_or(STAmount{0});
|
||||
|
||||
std::int64_t const newCount = totalRemainingOwnerCount(remainingOwnerCountDelta);
|
||||
|
||||
return newFee > beast::kZero || newCount > 0;
|
||||
}
|
||||
|
||||
template <typename ViewT>
|
||||
TER
|
||||
SponsorshipEntry<ViewT>::decrementPrefundedReserveCount(std::uint32_t const delta)
|
||||
requires Base::kIsWritable
|
||||
{
|
||||
if (delta == 0)
|
||||
return tesSUCCESS; // LCOV_EXCL_LINE
|
||||
|
||||
auto const currentReserveCount = (*this)->getFieldU32(sfRemainingOwnerCount);
|
||||
if (currentReserveCount < delta)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
// Already verified by checkReserve (sufficient RemainingOwnerCount)
|
||||
UNREACHABLE("xrpl::decrementPrefundedReserveCount : invalid reserve count");
|
||||
return tefINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
(*this)->at(sfRemainingOwnerCount) = currentReserveCount - delta;
|
||||
this->update();
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <typename ViewT>
|
||||
TER
|
||||
SponsorshipEntry<ViewT>::removeFromLedger()
|
||||
requires Base::kIsWritable
|
||||
{
|
||||
if (!this->exists())
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto& view = this->applyView();
|
||||
auto const j = this->journal();
|
||||
|
||||
auto const sponsorID = (**this)[sfOwner];
|
||||
auto const sponseeID = (**this)[sfSponsee];
|
||||
|
||||
// The sponsor owns the Sponsorship object, so deletion releases the
|
||||
// sponsor's owner reserve.
|
||||
auto const sponsorAccSle = view.peek(keylet::account(sponsorID));
|
||||
if (!sponsorAccSle)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!view.dirRemove(keylet::ownerDir(sponsorID), (**this)[sfOwnerNode], this->key(), false))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Unable to delete Sponsorship from sponsor.";
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
if (!view.dirRemove(keylet::ownerDir(sponseeID), (**this)[sfSponseeNode], this->key(), false))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Unable to delete Sponsorship from sponsee.";
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
decreaseOwnerCountForObject(view, sponsorAccSle, this->mutableRawSle(), 1, j);
|
||||
|
||||
// Return any prefunded fee amount to the sponsor before erasing the object.
|
||||
if ((*this)->isFieldPresent(sfFeeAmount))
|
||||
{
|
||||
(*sponsorAccSle)[sfBalance] += (*this)->getFieldAmount(sfFeeAmount);
|
||||
view.update(sponsorAccSle);
|
||||
}
|
||||
|
||||
this->erase();
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template class SponsorshipEntry<ReadView>;
|
||||
template class SponsorshipEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -181,15 +182,20 @@ adjustOwnerCountSigned(
|
||||
view.adjustOwnerCountHook(sponsorID, sponsorCurrent, sponsorAdjustment);
|
||||
}
|
||||
|
||||
auto const sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
|
||||
if (sponsorshipSle && adjustment > 0)
|
||||
SponsorshipEntryW sponsorship(sponsorID, accountID, view, j);
|
||||
if (sponsorship && adjustment > 0)
|
||||
{
|
||||
// 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 requires reserve (like other sf...OwnerCounts do).
|
||||
adjustOwnerCountImpl(
|
||||
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j);
|
||||
view,
|
||||
sponsorship.mutableRawSle(),
|
||||
sfRemainingOwnerCount,
|
||||
sponsorID,
|
||||
-adjustment,
|
||||
j);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,9 +441,8 @@ checkReserve(
|
||||
if (sponsorSle->getType() != ltACCOUNT_ROOT)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sle = ctx.view.read(
|
||||
keylet::sponsorship(
|
||||
sponsorSle->getAccountID(sfAccount), accSle->getAccountID(sfAccount)));
|
||||
SponsorshipEntryR const sle(
|
||||
sponsorSle->getAccountID(sfAccount), accSle->getAccountID(sfAccount), ctx.view, j);
|
||||
|
||||
// A reserve-sponsored tx must carry a sponsor signature
|
||||
// (cosigning path) and/or have a pre-existing sponsorship SLE
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <xrpl/json/to_string.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DelegateHelpers.h>
|
||||
@@ -430,8 +431,7 @@ Transactor::checkSponsor(ReadView const& view, STTx const& tx)
|
||||
|
||||
// If the transaction contains sfDelegate, the Sponsorship object should be
|
||||
// between the sponsor and the delegate.
|
||||
auto const sponsorshipSle =
|
||||
view.read(keylet::sponsorship(tx.getAccountID(sfSponsor), tx.getInitiator()));
|
||||
SponsorshipEntryR const sponsorshipSle(tx.getAccountID(sfSponsor), tx.getInitiator(), view);
|
||||
|
||||
// sponsorship object missing for pre-funded (no co-signing) tx
|
||||
if (!sponsorshipSle)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include <xrpl/tx/transactors/sponsor/SponsorshipSet.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
@@ -28,48 +28,6 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Compute the resulting RemainingOwnerCount using signed 64-bit arithmetic to
|
||||
// avoid unsigned wraparound. A missing SLE (object creation) or absent field
|
||||
// counts as zero. Callers handle the out-of-range results: a negative value is
|
||||
// clamped to zero (field absent) and overflow is rejected in preclaim.
|
||||
static std::int64_t
|
||||
totalRemainingOwnerCount(
|
||||
SLE::ConstRef sponsorshipSle,
|
||||
std::optional<std::int32_t> const& remainingOwnerCountDelta)
|
||||
{
|
||||
std::uint32_t const currentCount =
|
||||
sponsorshipSle ? (*sponsorshipSle)[~sfRemainingOwnerCount].value_or(0u) : 0u;
|
||||
return static_cast<std::int64_t>(currentCount) + remainingOwnerCountDelta.value_or(0);
|
||||
}
|
||||
|
||||
static bool
|
||||
hasSponsorshipBudget(
|
||||
SLE::ConstRef sponsorshipSle,
|
||||
std::optional<STAmount> const& feeAmountDelta,
|
||||
std::optional<std::int32_t> const& remainingOwnerCountDelta)
|
||||
{
|
||||
// sfFeeAmountDelta and sfRemainingOwnerCountDelta must be non-negative when creating a new
|
||||
// Sponsorship object.
|
||||
if (!sponsorshipSle)
|
||||
{
|
||||
if (feeAmountDelta.has_value() && *feeAmountDelta <= beast::kZero)
|
||||
return false;
|
||||
|
||||
if (remainingOwnerCountDelta.has_value() && *remainingOwnerCountDelta <= 0)
|
||||
return false;
|
||||
}
|
||||
// If the transaction omits a field, it keeps whatever the existing object holds,
|
||||
// so fall back to the current SLE value when the tx does not set it.
|
||||
STAmount const currentFee =
|
||||
sponsorshipSle ? (*sponsorshipSle)[~sfFeeAmount].value_or(STAmount{0}) : STAmount{0};
|
||||
STAmount const newFee = currentFee + feeAmountDelta.value_or(STAmount{0});
|
||||
|
||||
std::int64_t const newCount =
|
||||
totalRemainingOwnerCount(sponsorshipSle, remainingOwnerCountDelta);
|
||||
|
||||
return newFee > beast::kZero || newCount > 0;
|
||||
}
|
||||
|
||||
TxConsequences
|
||||
SponsorshipSet::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
@@ -176,78 +134,33 @@ SponsorshipSet::preclaim(PreclaimContext const& ctx)
|
||||
if (isPseudoAccount(sponsorAccSle) || isPseudoAccount(sponseeSle))
|
||||
return tecPSEUDO_ACCOUNT;
|
||||
|
||||
auto const sponsorshipSle = ctx.view.read(keylet::sponsorship(sponsorID, sponseeID));
|
||||
SponsorshipEntryR const sponsorship(sponsorID, sponseeID, ctx.view, ctx.j);
|
||||
|
||||
// Deleting a Sponsorship object requires the object to already exist.
|
||||
if (ctx.tx.isFlag(tfDeleteObject) && !sponsorshipSle)
|
||||
if (ctx.tx.isFlag(tfDeleteObject) && !sponsorship)
|
||||
return tecNO_ENTRY;
|
||||
|
||||
if (!ctx.tx.isFlag(tfDeleteObject))
|
||||
{
|
||||
// Reject if applying the delta would overflow uint32_t. A negative delta
|
||||
// that underflows is clamped to zero (field absent) rather than erroring.
|
||||
if (totalRemainingOwnerCount(sponsorshipSle, ctx.tx[~sfRemainingOwnerCountDelta]) >
|
||||
if (sponsorship.totalRemainingOwnerCount(ctx.tx[~sfRemainingOwnerCountDelta]) >
|
||||
static_cast<std::int64_t>(std::numeric_limits<std::uint32_t>::max()))
|
||||
return tecLIMIT_EXCEEDED;
|
||||
|
||||
// Reject creating or updating a Sponsorship that would be left with no
|
||||
// budget (neither a positive FeeAmount nor a positive RemainingOwnerCount).
|
||||
// Such an object is unusable yet still consumes the sponsor's reserve.
|
||||
if (!hasSponsorshipBudget(
|
||||
sponsorshipSle, ctx.tx[~sfFeeAmountDelta], ctx.tx[~sfRemainingOwnerCountDelta]))
|
||||
if (!sponsorship.hasBudget(ctx.tx[~sfFeeAmountDelta], ctx.tx[~sfRemainingOwnerCountDelta]))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
static TER
|
||||
deleteSponsorship(ApplyView& view, SLE::Ref sle, beast::Journal j)
|
||||
{
|
||||
if (!sle)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sponsorID = (*sle)[sfOwner];
|
||||
auto const sponseeID = (*sle)[sfSponsee];
|
||||
|
||||
// The sponsor owns the Sponsorship object, so deletion releases the
|
||||
// sponsor's owner reserve.
|
||||
auto const sponsorAccSle = view.peek(keylet::account(sponsorID));
|
||||
if (!sponsorAccSle)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!view.dirRemove(keylet::ownerDir(sponsorID), (*sle)[sfOwnerNode], sle->key(), false))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Unable to delete Sponsorship from sponsor.";
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
if (!view.dirRemove(keylet::ownerDir(sponseeID), (*sle)[sfSponseeNode], sle->key(), false))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Unable to delete Sponsorship from sponsee.";
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
decreaseOwnerCountForObject(view, sponsorAccSle, sle, 1, j);
|
||||
|
||||
// Return any prefunded fee amount to the sponsor before erasing the object.
|
||||
if (sle->isFieldPresent(sfFeeAmount))
|
||||
{
|
||||
(*sponsorAccSle)[sfBalance] += sle->getFieldAmount(sfFeeAmount);
|
||||
view.update(sponsorAccSle);
|
||||
}
|
||||
|
||||
view.erase(sle);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
SponsorshipSet::createSponsorship(
|
||||
Keylet const& sponsorshipKeylet,
|
||||
SponsorshipEntryW& sponsorship,
|
||||
AccountID const& sponsorID,
|
||||
AccountID const& sponseeID,
|
||||
SLE::Ref sponsorAccSle,
|
||||
@@ -260,7 +173,7 @@ SponsorshipSet::createSponsorship(
|
||||
bool const hasPositiveFeeAmount = feeAmountDelta.has_value() && *feeAmountDelta > beast::kZero;
|
||||
|
||||
// Create a new Sponsorship object between the sponsor and sponsee.
|
||||
auto const newSle = std::make_shared<SLE>(sponsorshipKeylet);
|
||||
sponsorship.newSLE();
|
||||
STAmount sponsorBalanceAfterFee = (*sponsorAccSle)[sfBalance];
|
||||
// sfFeeAmountDelta must be positive if the sponsorship object doesn't exist. This is
|
||||
// checked in preclaim.
|
||||
@@ -268,8 +181,8 @@ SponsorshipSet::createSponsorship(
|
||||
!feeAmountDelta.has_value() || *feeAmountDelta > beast::kZero,
|
||||
"xrpl::SponsorshipSet::doApply : new sponsorship has positive fee amount");
|
||||
|
||||
(*newSle)[sfOwner] = sponsorID;
|
||||
(*newSle)[sfSponsee] = sponseeID;
|
||||
(*sponsorship)[sfOwner] = sponsorID;
|
||||
(*sponsorship)[sfSponsee] = sponseeID;
|
||||
if (feeAmountDelta && feeAmountDelta->xrp() > sponsorBalanceAfterFee.xrp())
|
||||
return tecUNFUNDED;
|
||||
|
||||
@@ -292,14 +205,14 @@ SponsorshipSet::createSponsorship(
|
||||
if (hasPositiveFeeAmount)
|
||||
{
|
||||
// New object: FeeAmount starts absent, so deduct and record the full amount
|
||||
(*newSle)[sfFeeAmount] = *feeAmountDelta;
|
||||
(*sponsorship)[sfFeeAmount] = *feeAmountDelta;
|
||||
(*sponsorAccSle)[sfBalance] -= *feeAmountDelta;
|
||||
}
|
||||
|
||||
if (maxFee && *maxFee > beast::kZero)
|
||||
(*newSle)[sfMaxFee] = *maxFee;
|
||||
(*sponsorship)[sfMaxFee] = *maxFee;
|
||||
if (remainingOwnerCountDelta && *remainingOwnerCountDelta > 0)
|
||||
(*newSle)[sfRemainingOwnerCount] = *remainingOwnerCountDelta;
|
||||
(*sponsorship)[sfRemainingOwnerCount] = *remainingOwnerCountDelta;
|
||||
|
||||
std::uint32_t flags = 0;
|
||||
if (ctx_.tx.isFlag(tfSponsorshipSetRequireSignForFee))
|
||||
@@ -308,25 +221,25 @@ SponsorshipSet::createSponsorship(
|
||||
if (ctx_.tx.isFlag(tfSponsorshipSetRequireSignForReserve))
|
||||
flags |= lsfSponsorshipRequireSignForReserve;
|
||||
|
||||
(*newSle)[sfFlags] = flags;
|
||||
(*sponsorship)[sfFlags] = flags;
|
||||
|
||||
auto const sponsorPage = view().dirInsert(
|
||||
keylet::ownerDir(sponsorID), sponsorshipKeylet, describeOwnerDir(sponsorID));
|
||||
keylet::ownerDir(sponsorID), sponsorship.keylet(), describeOwnerDir(sponsorID));
|
||||
if (!sponsorPage)
|
||||
return tecDIR_FULL; // LCOV_EXCL_LINE
|
||||
(*newSle)[sfOwnerNode] = *sponsorPage;
|
||||
(*sponsorship)[sfOwnerNode] = *sponsorPage;
|
||||
|
||||
auto const sponseePage = view().dirInsert(
|
||||
keylet::ownerDir(sponseeID), sponsorshipKeylet, describeOwnerDir(sponseeID));
|
||||
keylet::ownerDir(sponseeID), sponsorship.keylet(), describeOwnerDir(sponseeID));
|
||||
if (!sponseePage)
|
||||
return tecDIR_FULL; // LCOV_EXCL_LINE
|
||||
(*newSle)[sfSponseeNode] = *sponseePage;
|
||||
(*sponsorship)[sfSponseeNode] = *sponseePage;
|
||||
|
||||
// NOLINTNEXTLINE(readability-suspicious-call-argument)
|
||||
increaseOwnerCount(view(), sponsorAccSle, reserveSponsorAccSle, 1, ctx_.journal);
|
||||
addSponsorToLedgerEntry(newSle, reserveSponsorAccSle);
|
||||
addSponsorToLedgerEntry(sponsorship.mutableRawSle(), reserveSponsorAccSle);
|
||||
|
||||
ctx_.view().insert(newSle);
|
||||
sponsorship.insert();
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -346,15 +259,14 @@ SponsorshipSet::doApply()
|
||||
if (!ctx_.view().exists(keylet::account(sponseeID)))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sponsorshipKeylet = keylet::sponsorship(sponsorID, sponseeID);
|
||||
auto const sponsorshipSle = ctx_.view().peek(sponsorshipKeylet);
|
||||
SponsorshipEntryW sponsorship(sponsorID, sponseeID, ctx_.view(), ctx_.journal);
|
||||
|
||||
if (ctx_.tx.isFlag(tfDeleteObject))
|
||||
{
|
||||
if (!sponsorshipSle)
|
||||
if (!sponsorship)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return deleteSponsorship(ctx_.view(), sponsorshipSle, ctx_.journal);
|
||||
return sponsorship.removeFromLedger();
|
||||
}
|
||||
|
||||
auto const feeAmountDelta = ctx_.tx[~sfFeeAmountDelta];
|
||||
@@ -365,17 +277,17 @@ SponsorshipSet::doApply()
|
||||
if (!reserveSponsorAccSle)
|
||||
return reserveSponsorAccSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
if (!sponsorshipSle)
|
||||
if (!sponsorship)
|
||||
{
|
||||
return createSponsorship(
|
||||
sponsorshipKeylet, sponsorID, sponseeID, sponsorAccSle, *reserveSponsorAccSle);
|
||||
sponsorship, sponsorID, sponseeID, sponsorAccSle, *reserveSponsorAccSle);
|
||||
}
|
||||
|
||||
// Update the existing Sponsorship object.
|
||||
if (feeAmountDelta)
|
||||
{
|
||||
auto actualDelta = feeAmountDelta.value();
|
||||
auto const currentFee = (*sponsorshipSle)[~sfFeeAmount].valueOr(XRPAmount{0});
|
||||
auto const currentFee = (*sponsorship)[~sfFeeAmount].valueOr(XRPAmount{0});
|
||||
|
||||
// Clamp negative delta to avoid underflow.
|
||||
if (actualDelta < beast::kZero && -actualDelta > currentFee)
|
||||
@@ -408,11 +320,11 @@ SponsorshipSet::doApply()
|
||||
newFee >= beast::kZero, "xrpl::SponsorshipSet::doApply : new fee is non-negative");
|
||||
if (newFee == beast::kZero)
|
||||
{
|
||||
sponsorshipSle->makeFieldAbsent(sfFeeAmount);
|
||||
sponsorship->makeFieldAbsent(sfFeeAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*sponsorshipSle)[sfFeeAmount] = newFee;
|
||||
(*sponsorship)[sfFeeAmount] = newFee;
|
||||
}
|
||||
ctx_.view().update(sponsorAccSle);
|
||||
}
|
||||
@@ -421,34 +333,34 @@ SponsorshipSet::doApply()
|
||||
{
|
||||
if (*maxFee == beast::kZero)
|
||||
{
|
||||
(*sponsorshipSle).makeFieldAbsent(sfMaxFee);
|
||||
(*sponsorship).makeFieldAbsent(sfMaxFee);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*sponsorshipSle)[sfMaxFee] = *maxFee;
|
||||
(*sponsorship)[sfMaxFee] = *maxFee;
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingOwnerCountDelta)
|
||||
{
|
||||
std::int64_t const newCount =
|
||||
totalRemainingOwnerCount(sponsorshipSle, remainingOwnerCountDelta);
|
||||
sponsorship.totalRemainingOwnerCount(remainingOwnerCountDelta);
|
||||
// Overflow is rejected in preclaim; underflow clamps to zero (field absent).
|
||||
XRPL_ASSERT(
|
||||
newCount <= static_cast<std::int64_t>(std::numeric_limits<std::uint32_t>::max()),
|
||||
"xrpl::SponsorshipSet::doApply : RemainingOwnerCount does not overflow");
|
||||
if (newCount <= 0)
|
||||
{
|
||||
sponsorshipSle->makeFieldAbsent(sfRemainingOwnerCount);
|
||||
sponsorship->makeFieldAbsent(sfRemainingOwnerCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
sponsorshipSle->at(sfRemainingOwnerCount) = static_cast<std::uint32_t>(newCount);
|
||||
sponsorship->at(sfRemainingOwnerCount) = static_cast<std::uint32_t>(newCount);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply requested flag changes.
|
||||
auto flags = sponsorshipSle->getFieldU32(sfFlags);
|
||||
auto flags = sponsorship->getFieldU32(sfFlags);
|
||||
if (ctx_.tx.isFlag(tfSponsorshipSetRequireSignForFee))
|
||||
flags |= lsfSponsorshipRequireSignForFee;
|
||||
|
||||
@@ -461,10 +373,10 @@ SponsorshipSet::doApply()
|
||||
if (ctx_.tx.isFlag(tfSponsorshipClearRequireSignForReserve))
|
||||
flags &= ~lsfSponsorshipRequireSignForReserve;
|
||||
|
||||
if (flags != (*sponsorshipSle)[sfFlags])
|
||||
(*sponsorshipSle)[sfFlags] = flags;
|
||||
if (flags != (*sponsorship)[sfFlags])
|
||||
(*sponsorship)[sfFlags] = flags;
|
||||
|
||||
view().update(sponsorshipSle);
|
||||
sponsorship.update();
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -68,29 +69,6 @@ decrementSponsorCount(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
// Consume the sponsor's pre-funded reserve budget and lowers the Sponsorship
|
||||
// object's RemainingOwnerCount.
|
||||
static TER
|
||||
decrementPrefundedReserveCount(ApplyView& view, SLE::Ref sponsorshipSle, std::uint32_t const delta)
|
||||
{
|
||||
if (delta == 0)
|
||||
return tesSUCCESS; // LCOV_EXCL_LINE
|
||||
|
||||
auto const currentReserveCount = sponsorshipSle->getFieldU32(sfRemainingOwnerCount);
|
||||
if (currentReserveCount < delta)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
// Already verified by checkReserve (sufficient RemainingOwnerCount)
|
||||
UNREACHABLE("xrpl::decrementPrefundedReserveCount : invalid reserve count");
|
||||
return tefINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
sponsorshipSle->at(sfRemainingOwnerCount) = currentReserveCount - delta;
|
||||
view.update(sponsorshipSle);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
SponsorshipTransfer::getFlagsMask(PreflightContext const& ctx)
|
||||
{
|
||||
@@ -405,12 +383,11 @@ SponsorshipTransfer::doApply()
|
||||
objectSle->setAccountID(sponsorField, newSponsorID);
|
||||
view().update(objectSle);
|
||||
|
||||
auto const sponsorshipSle = view().peek(keylet::sponsorship(newSponsorID, sponseeID));
|
||||
if (sponsorshipSle)
|
||||
SponsorshipEntryW sponsorship(newSponsorID, sponseeID, view(), ctx_.journal);
|
||||
if (sponsorship)
|
||||
{
|
||||
// Update ReserveCount for sponsorship object if it exists
|
||||
if (auto const ter =
|
||||
decrementPrefundedReserveCount(view(), sponsorshipSle, ownerCountDelta);
|
||||
if (auto const ter = sponsorship.decrementPrefundedReserveCount(ownerCountDelta);
|
||||
!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user