1#include <xrpl/tx/transactors/sponsor/SponsorshipSet.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/Journal.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/core/ServiceRegistry.h>
8#include <xrpl/ledger/ApplyView.h>
9#include <xrpl/ledger/ReadView.h>
10#include <xrpl/ledger/helpers/AccountRootHelpers.h>
11#include <xrpl/ledger/helpers/DirectoryHelpers.h>
12#include <xrpl/ledger/helpers/SponsorHelpers.h>
13#include <xrpl/protocol/AccountID.h>
14#include <xrpl/protocol/Indexes.h>
15#include <xrpl/protocol/Keylet.h>
16#include <xrpl/protocol/LedgerFormats.h>
17#include <xrpl/protocol/SField.h>
18#include <xrpl/protocol/STAmount.h>
19#include <xrpl/protocol/TER.h>
20#include <xrpl/protocol/TxFlags.h>
21#include <xrpl/tx/Transactor.h>
41 sponsorshipSle ? (*sponsorshipSle)[~sfRemainingOwnerCount].value_or(0u) : 0u;
58 if (remainingOwnerCountDelta.
has_value() && *remainingOwnerCountDelta <= 0)
64 sponsorshipSle ? (*sponsorshipSle)[~sfFeeAmount].value_or(
STAmount{0}) :
STAmount{0};
76 auto const feeAmount = ctx.
tx[~sfFeeAmountDelta];
84 return tfSponsorshipSetMask;
90 if (ctx.
tx.
isFlag(tfSponsorshipSetRequireSignForFee) &&
91 ctx.
tx.
isFlag(tfSponsorshipClearRequireSignForFee))
93 if (ctx.
tx.
isFlag(tfSponsorshipSetRequireSignForReserve) &&
94 ctx.
tx.
isFlag(tfSponsorshipClearRequireSignForReserve))
102 if (hasSponsor == hasSponsee)
105 auto const sponsorID = ctx.
tx[~sfCounterpartySponsor].value_or(account);
106 auto const sponseeID = ctx.
tx[~sfSponsee].value_or(account);
108 if (sponsorID == sponseeID)
114 constexpr std::uint32_t kModifyFlags = tfSponsorshipSetRequireSignForFee |
115 tfSponsorshipSetRequireSignForReserve | tfSponsorshipClearRequireSignForFee |
116 tfSponsorshipClearRequireSignForReserve;
130 if (account != sponsorID)
134 if (
auto const feeAmt = ctx.
tx[~sfFeeAmountDelta];
139 if (
auto const maxFee = ctx.
tx[~sfMaxFee];
144 if (
auto const remainingOwnerCountDelta = ctx.
tx[~sfRemainingOwnerCountDelta];
145 remainingOwnerCountDelta && *remainingOwnerCountDelta == 0)
161 auto const sponsorID = ctx.
tx[~sfCounterpartySponsor].value_or(ctx.
tx[sfAccount]);
162 auto const sponseeID = ctx.
tx[~sfSponsee].value_or(ctx.
tx[sfAccount]);
164 if (sponseeID == sponsorID)
182 if (ctx.
tx.
isFlag(tfDeleteObject) && !sponsorshipSle)
197 sponsorshipSle, ctx.
tx[~sfFeeAmountDelta], ctx.
tx[~sfRemainingOwnerCountDelta]))
210 auto const sponsorID = (*sle)[sfOwner];
211 auto const sponseeID = (*sle)[sfSponsee];
222 JLOG(j.
fatal()) <<
"Unable to delete Sponsorship from sponsor.";
229 JLOG(j.
fatal()) <<
"Unable to delete Sponsorship from sponsee.";
237 if (sle->isFieldPresent(sfFeeAmount))
239 (*sponsorAccSle)[sfBalance] += sle->getFieldAmount(sfFeeAmount);
240 view.
update(sponsorAccSle);
250 Keylet const& sponsorshipKeylet,
256 auto const feeAmountDelta =
ctx_.tx[~sfFeeAmountDelta];
257 auto const maxFee =
ctx_.tx[~sfMaxFee];
258 auto const remainingOwnerCountDelta =
ctx_.tx[~sfRemainingOwnerCountDelta];
260 bool const hasPositiveFeeAmount = feeAmountDelta.has_value() && *feeAmountDelta >
beast::kZero;
264 STAmount sponsorBalanceAfterFee = (*sponsorAccSle)[sfBalance];
268 !feeAmountDelta.has_value() || *feeAmountDelta >
beast::kZero,
269 "xrpl::SponsorshipSet::doApply : new sponsorship has positive fee amount");
271 (*newSle)[sfOwner] = sponsorID;
272 (*newSle)[sfSponsee] = sponseeID;
273 if (feeAmountDelta && feeAmountDelta->xrp() > sponsorBalanceAfterFee.
xrp())
276 if (hasPositiveFeeAmount)
277 sponsorBalanceAfterFee -= *feeAmountDelta;
280 ctx_.getApplyViewContext(),
282 sponsorBalanceAfterFee.
xrp(),
283 reserveSponsorAccSle,
284 {.ownerCountDelta = 1},
292 if (hasPositiveFeeAmount)
295 (*newSle)[sfFeeAmount] = *feeAmountDelta;
296 (*sponsorAccSle)[sfBalance] -= *feeAmountDelta;
300 (*newSle)[sfMaxFee] = *maxFee;
301 if (remainingOwnerCountDelta && *remainingOwnerCountDelta > 0)
302 (*newSle)[sfRemainingOwnerCount] = *remainingOwnerCountDelta;
305 if (
ctx_.tx.isFlag(tfSponsorshipSetRequireSignForFee))
306 flags |= lsfSponsorshipRequireSignForFee;
308 if (
ctx_.tx.isFlag(tfSponsorshipSetRequireSignForReserve))
309 flags |= lsfSponsorshipRequireSignForReserve;
311 (*newSle)[sfFlags] = flags;
317 (*newSle)[sfOwnerNode] = *sponsorPage;
323 (*newSle)[sfSponseeNode] = *sponseePage;
329 ctx_.view().insert(newSle);
336 auto const sponsorID =
ctx_.tx[~sfCounterpartySponsor].value_or(
accountID_);
339 if (sponseeID == sponsorID)
350 auto const sponsorshipSle =
ctx_.view().peek(sponsorshipKeylet);
352 if (
ctx_.tx.isFlag(tfDeleteObject))
360 auto const feeAmountDelta =
ctx_.tx[~sfFeeAmountDelta];
361 auto const maxFee =
ctx_.tx[~sfMaxFee];
362 auto const remainingOwnerCountDelta =
ctx_.tx[~sfRemainingOwnerCountDelta];
365 if (!reserveSponsorAccSle)
366 return reserveSponsorAccSle.error();
371 sponsorshipKeylet, sponsorID, sponseeID, sponsorAccSle, *reserveSponsorAccSle);
377 auto actualDelta = feeAmountDelta.value();
378 auto const currentFee = (*sponsorshipSle)[~sfFeeAmount].valueOr(
XRPAmount{0});
381 if (actualDelta < beast::kZero && -actualDelta > currentFee)
382 actualDelta = -currentFee;
384 if (actualDelta >
beast::kZero && actualDelta > (*sponsorAccSle)[sfBalance])
389 (*sponsorAccSle)[sfBalance] -= actualDelta;
392 ctx_.getApplyViewContext(),
394 (*sponsorAccSle)[sfBalance]->xrp(),
395 *reserveSponsorAccSle,
404 STAmount const newFee = currentFee + actualDelta;
407 newFee >=
beast::kZero,
"xrpl::SponsorshipSet::doApply : new fee is non-negative");
410 sponsorshipSle->makeFieldAbsent(sfFeeAmount);
414 (*sponsorshipSle)[sfFeeAmount] = newFee;
416 ctx_.view().update(sponsorAccSle);
423 (*sponsorshipSle).makeFieldAbsent(sfMaxFee);
427 (*sponsorshipSle)[sfMaxFee] = *maxFee;
431 if (remainingOwnerCountDelta)
438 "xrpl::SponsorshipSet::doApply : RemainingOwnerCount does not overflow");
441 sponsorshipSle->makeFieldAbsent(sfRemainingOwnerCount);
445 sponsorshipSle->at(sfRemainingOwnerCount) =
static_cast<std::uint32_t>(newCount);
450 auto flags = sponsorshipSle->getFieldU32(sfFlags);
451 if (
ctx_.tx.isFlag(tfSponsorshipSetRequireSignForFee))
452 flags |= lsfSponsorshipRequireSignForFee;
454 if (
ctx_.tx.isFlag(tfSponsorshipClearRequireSignForFee))
455 flags &= ~lsfSponsorshipRequireSignForFee;
457 if (
ctx_.tx.isFlag(tfSponsorshipSetRequireSignForReserve))
458 flags |= lsfSponsorshipRequireSignForReserve;
460 if (
ctx_.tx.isFlag(tfSponsorshipClearRequireSignForReserve))
461 flags &= ~lsfSponsorshipRequireSignForReserve;
463 if (flags != (*sponsorshipSle)[sfFlags])
464 (*sponsorshipSle)[sfFlags] = flags;
A generic endpoint for log messages.
Writeable view to a ledger, for applying a transaction.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
virtual void erase(SLE::ref sle)=0
Remove a peeked SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(SLE::ref)> const &describe)
Insert an entry to a directory.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry const > const & const_ref
bool isFlag(std::uint32_t) const
bool isFieldPresent(SField const &field) const
AccountID getAccountID(SField const &field) const
std::uint32_t getFlags() const
AccountID const accountID_
Class describing the consequences to the account of applying a transaction if the transaction consume...
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet sponsorship(AccountID const &sponsor, AccountID const &sponsee) noexcept
A Sponsorship.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
void decreaseOwnerCountForObject(ApplyView &view, SLE::ref accountSle, SLE::ref objectSle, std::uint32_t count, beast::Journal j)
Decrease owner-count fields for an existing ledger object.
bool isXRP(AccountID const &c)
void increaseOwnerCount(ApplyView &view, SLE::ref accountSle, SLE::ref sponsorSle, std::uint32_t count, beast::Journal j)
Increase owner-count fields when the caller supplies the sponsor.
static bool hasSponsorshipBudget(SLE::const_ref sponsorshipSle, std::optional< STAmount > const &feeAmountDelta, std::optional< std::int32_t > const &remainingOwnerCountDelta)
static std::int64_t totalRemainingOwnerCount(SLE::const_ref sponsorshipSle, std::optional< std::int32_t > const &remainingOwnerCountDelta)
std::expected< SLE::pointer, TER > getTxReserveSponsor(ApplyViewContext ctx)
Return a mutable SLE for the transaction's reserve sponsor account.
void addSponsorToLedgerEntry(SLE::ref sle, SLE::const_ref sponsorSle, SF_ACCOUNT const &field=sfSponsor)
Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
TERSubset< CanCvtToNotTEC > NotTEC
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TER checkReserve(ApplyViewContext ctx, SLE::const_ref accSle, XRPAmount accBalance, SLE::const_ref sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
bool isPseudoAccount(SLE::const_pointer sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
static TER deleteSponsorship(ApplyView &view, SLE::ref sle, beast::Journal j)
constexpr FlagValue tfUniversalMask
A pair of SHAMap key and LedgerEntryType.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.