refactor: Move SponsorshipTransfer code around, add some comments (#7662)

This commit is contained in:
Mayukha Vadari
2026-06-30 14:06:20 -04:00
committed by GitHub
parent f9af579690
commit 09b5cd9879
6 changed files with 142 additions and 102 deletions

View File

@@ -0,0 +1,19 @@
#pragma once
#include <cstddef>
#include <cstdint>
namespace xrpl {
constexpr uint32_t kMinOracleReserveCount = 1;
constexpr uint32_t kMaxOracleReserveCount = 2;
constexpr std::size_t kOracleReserveCountThreshold = 5;
inline uint32_t
calculateOracleReserve(std::size_t priceDataSeriesCount)
{
return priceDataSeriesCount > kOracleReserveCountThreshold ? kMaxOracleReserveCount
: kMinOracleReserveCount;
}
} // namespace xrpl

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/OracleHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STTx.h>
@@ -123,4 +124,99 @@ removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field = sfSponsor)
sle->makeFieldAbsent(field);
}
template <typename T>
inline std::optional<AccountID>
getLedgerEntryOwner(ReadView const& view, T const& sle, AccountID const& account)
{
switch (sle->getType())
{
case ltCHECK:
case ltESCROW:
case ltPAYCHAN:
case ltMPTOKEN:
case ltDELEGATE:
case ltDEPOSIT_PREAUTH:
return sle->getAccountID(sfAccount);
case ltMPTOKEN_ISSUANCE:
return sle->getAccountID(sfIssuer);
case ltSIGNER_LIST: {
auto const signerList = view.read(keylet::signers(account));
if (!signerList)
return std::nullopt;
if (signerList->key() == sle->key())
return account;
return std::nullopt;
}
case ltCREDENTIAL: {
if (sle->isFlag(lsfAccepted))
return sle->getAccountID(sfSubject);
return sle->getAccountID(sfIssuer);
}
case ltRIPPLE_STATE: {
if (sle->isFlag(lsfHighReserve))
{
auto const highAccount = sle->getFieldAmount(sfHighLimit).getIssuer();
if (highAccount == account)
return highAccount;
}
if (sle->isFlag(lsfLowReserve))
{
auto const lowAccount = sle->getFieldAmount(sfLowLimit).getIssuer();
if (lowAccount == account)
return lowAccount;
}
return std::nullopt;
}
default:
UNREACHABLE("Object is not supported by sponsorship.");
return std::nullopt;
};
}
template <typename T>
inline std::uint32_t
getLedgerEntryOwnerCount(T const& sle)
{
switch (sle->getType())
{
case ltORACLE: {
return calculateOracleReserve(sle->getFieldArray(sfPriceDataSeries).size());
}
// Vaults require 2 owner counts (the vault and a pseudo-account)
case ltVAULT:
return 2;
default:
return 1;
}
};
template <typename T>
inline SF_ACCOUNT const&
getLedgerEntrySponsorField(T const& sle, AccountID const& owner)
{
switch (sle->getType())
{
case ltRIPPLE_STATE: {
if (sle->isFlag(lsfHighReserve))
{
auto const highAccount = sle->getFieldAmount(sfHighLimit).getIssuer();
if (highAccount == owner)
return sfHighSponsor;
}
if (sle->isFlag(lsfLowReserve))
{
auto const lowAccount = sle->getFieldAmount(sfLowLimit).getIssuer();
if (lowAccount == owner)
return sfLowSponsor;
}
// LCOV_EXCL_START
UNREACHABLE("Should not happen. Owner should be checked before calling this function.");
return sfSponsor;
// LCOV_EXCL_STOP
}
default:
return sfSponsor;
}
};
} // namespace xrpl

View File

@@ -22,12 +22,6 @@ public:
{
}
static uint32_t
calculateOracleReserve(std::size_t count)
{
return count > 5 ? 2 : 1;
}
static NotTEC
preflight(PreflightContext const& ctx);

View File

@@ -4,13 +4,13 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/OracleHelpers.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/transactors/oracle/OracleSet.h>
#include <cstdint>
#include <memory>
@@ -62,7 +62,7 @@ SponsorshipOwnerCountsMatch::visitEntry(
if (!sle->isFieldPresent(sfSponsor))
return 0;
auto const priceDataSeries = sle->getFieldArray(sfPriceDataSeries);
return OracleSet::calculateOracleReserve(priceDataSeries.size());
return calculateOracleReserve(priceDataSeries.size());
}
case ltVAULT: {
if (!sle->isFieldPresent(sfSponsor))

View File

@@ -53,6 +53,9 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx)
if (ctx.tx.isFlag(tfSponsorshipCreate))
{
// Sponsor must be included
// SponsorFlags.spfSponsorReserve must be included
// Sponsee must be excluded
if (!isReserveSponsored(ctx.tx))
{
JLOG(ctx.j.debug())
@@ -68,6 +71,9 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx)
}
if (ctx.tx.isFlag(tfSponsorshipReassign))
{
// Sponsor must be included
// SponsorFlags.spfSponsorReserve must be included
// Sponsee must be excluded
if (!isReserveSponsored(ctx.tx))
{
JLOG(ctx.j.debug())
@@ -83,6 +89,8 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx)
}
if (ctx.tx.isFlag(tfSponsorshipEnd))
{
// Sponsor must be excluded
// SponsorFlags.spfSponsorReserve must be excluded
if (isReserveSponsored(ctx.tx))
{
JLOG(ctx.j.debug())
@@ -116,96 +124,18 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx)
return tesSUCCESS;
}
template <typename T>
inline std::optional<AccountID>
getLedgerEntryOwner(ReadView const& view, T const& sle, AccountID const& account)
{
switch (sle->getType())
{
case ltCHECK:
case ltESCROW:
case ltPAYCHAN:
case ltMPTOKEN:
case ltDELEGATE:
case ltDEPOSIT_PREAUTH:
return sle->getAccountID(sfAccount);
case ltMPTOKEN_ISSUANCE:
return sle->getAccountID(sfIssuer);
case ltSIGNER_LIST: {
auto const signerList = view.read(keylet::signers(account));
if (!signerList)
return std::nullopt;
if (signerList->key() == sle->key())
return account;
return std::nullopt;
}
case ltCREDENTIAL: {
if (sle->isFlag(lsfAccepted))
return sle->getAccountID(sfSubject);
return sle->getAccountID(sfIssuer);
}
case ltRIPPLE_STATE: {
if (sle->isFlag(lsfHighReserve))
{
auto const highAccount = sle->getFieldAmount(sfHighLimit).getIssuer();
if (highAccount == account)
return highAccount;
}
if (sle->isFlag(lsfLowReserve))
{
auto const lowAccount = sle->getFieldAmount(sfLowLimit).getIssuer();
if (lowAccount == account)
return lowAccount;
}
return std::nullopt;
}
default:
UNREACHABLE("Object is not supported by sponsorship.");
return std::nullopt;
};
}
template <typename T>
inline SF_ACCOUNT const&
getLedgerEntrySponsorField(T const& sle, AccountID const& owner)
{
switch (sle->getType())
{
case ltRIPPLE_STATE: {
if (sle->isFlag(lsfHighReserve))
{
auto const highAccount = sle->getFieldAmount(sfHighLimit).getIssuer();
if (highAccount == owner)
return sfHighSponsor;
}
if (sle->isFlag(lsfLowReserve))
{
auto const lowAccount = sle->getFieldAmount(sfLowLimit).getIssuer();
if (lowAccount == owner)
return sfLowSponsor;
}
// LCOV_EXCL_START
UNREACHABLE("Should not happen. Owner should be checked before calling this function.");
return sfSponsor;
// LCOV_EXCL_STOP
}
default:
return sfSponsor;
}
};
TER
SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
{
auto const index = ctx.tx[~sfObjectID];
auto const newSponsorSle = getTxReserveSponsor(ctx.view, ctx.tx);
if (!newSponsorSle)
return newSponsorSle.error(); // LCOV_EXCL_LINE
auto const newSponsorSleExpected = getTxReserveSponsor(ctx.view, ctx.tx);
if (!newSponsorSleExpected)
return newSponsorSleExpected.error(); // LCOV_EXCL_LINE
auto const newSponsorSle = *newSponsorSleExpected;
bool const isObjectSponsor = index != std::nullopt;
bool const isObjectSponsor = !!index;
auto const account = ctx.tx[sfAccount];
auto const sponseeID = ctx.tx[~sfSponsee].value_or(account);
auto const sponseeSle = ctx.view.read(keylet::account(sponseeID));
if (!sponseeSle)
@@ -243,23 +173,23 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
std::uint32_t const ownerCountDelta = 1;
auto const owner = getLedgerEntryOwner(ctx.view, sle, sponseeID);
if (!owner || owner != sponseeID)
if (!owner.has_value() || owner.value() != sponseeID)
return tecNO_PERMISSION;
auto const& sponsorField = getLedgerEntrySponsorField(sle, *owner);
auto const& sponsorField = getLedgerEntrySponsorField(sle, owner.value());
if (ctx.tx.isFlag(tfSponsorshipCreate))
{
if (!*newSponsorSle)
if (!newSponsorSle)
return tecNO_PERMISSION;
// check object is not sponsored yet
// check that the object is not sponsored yet
if (sle->isFieldPresent(sponsorField))
return tecNO_PERMISSION;
}
else if (ctx.tx.isFlag(tfSponsorshipReassign))
{
if (!*newSponsorSle)
if (!newSponsorSle)
return tecNO_PERMISSION;
// check object is already ctx.sponsored
@@ -268,7 +198,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
}
else if (ctx.tx.isFlag(tfSponsorshipEnd))
{
if (*newSponsorSle)
if (newSponsorSle)
return tecNO_PERMISSION;
// check object is sponsored
@@ -288,7 +218,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
ctx.tx,
sponseeSle,
sponseeSle->getFieldAmount(sfBalance),
*newSponsorSle,
newSponsorSle,
ownerCountDelta,
0,
ctx.j);
@@ -299,7 +229,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
{
if (ctx.tx.isFlag(tfSponsorshipCreate))
{
if (!*newSponsorSle)
if (!newSponsorSle)
return tecNO_PERMISSION;
// check account is not sponsored yet
@@ -308,7 +238,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
}
else if (ctx.tx.isFlag(tfSponsorshipReassign))
{
if (!*newSponsorSle)
if (!newSponsorSle)
return tecNO_PERMISSION;
// check account is already sponsored
@@ -317,7 +247,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
}
else if (ctx.tx.isFlag(tfSponsorshipEnd))
{
if (*newSponsorSle)
if (newSponsorSle)
return tecNO_PERMISSION;
// check account is sponsored
@@ -340,7 +270,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
ctx.tx,
sponseeSle,
sponseeSle->getFieldAmount(sfBalance),
*newSponsorSle,
newSponsorSle,
0,
1,
ctx.j);

View File

@@ -42,6 +42,7 @@
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>