diff --git a/include/xrpl/ledger/helpers/OracleHelpers.h b/include/xrpl/ledger/helpers/OracleHelpers.h new file mode 100644 index 0000000000..635e47c564 --- /dev/null +++ b/include/xrpl/ledger/helpers/OracleHelpers.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +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 diff --git a/include/xrpl/ledger/helpers/SponsorHelpers.h b/include/xrpl/ledger/helpers/SponsorHelpers.h index 65dad72897..93614e5e17 100644 --- a/include/xrpl/ledger/helpers/SponsorHelpers.h +++ b/include/xrpl/ledger/helpers/SponsorHelpers.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -123,4 +124,99 @@ removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field = sfSponsor) sle->makeFieldAbsent(field); } +template +inline std::optional +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 +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 +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 diff --git a/include/xrpl/tx/transactors/oracle/OracleSet.h b/include/xrpl/tx/transactors/oracle/OracleSet.h index 51ed7be3dc..831c11b8c4 100644 --- a/include/xrpl/tx/transactors/oracle/OracleSet.h +++ b/include/xrpl/tx/transactors/oracle/OracleSet.h @@ -22,12 +22,6 @@ public: { } - static uint32_t - calculateOracleReserve(std::size_t count) - { - return count > 5 ? 2 : 1; - } - static NotTEC preflight(PreflightContext const& ctx); diff --git a/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp b/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp index f4db96a643..9ebc008473 100644 --- a/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp +++ b/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp @@ -4,13 +4,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include @@ -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)) diff --git a/src/libxrpl/tx/transactors/Sponsor/SponsorshipTransfer.cpp b/src/libxrpl/tx/transactors/Sponsor/SponsorshipTransfer.cpp index 0c98511a5c..deea6edc84 100644 --- a/src/libxrpl/tx/transactors/Sponsor/SponsorshipTransfer.cpp +++ b/src/libxrpl/tx/transactors/Sponsor/SponsorshipTransfer.cpp @@ -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 -inline std::optional -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 -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); diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index 6b974c28a1..a615426463 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include