diff --git a/include/xrpl/ledger/helpers/OracleHelpers.h b/include/xrpl/ledger/helpers/OracleHelpers.h index 635e47c564..7ba69d1c52 100644 --- a/include/xrpl/ledger/helpers/OracleHelpers.h +++ b/include/xrpl/ledger/helpers/OracleHelpers.h @@ -5,11 +5,11 @@ namespace xrpl { -constexpr uint32_t kMinOracleReserveCount = 1; -constexpr uint32_t kMaxOracleReserveCount = 2; +constexpr std::uint32_t kMinOracleReserveCount = 1; +constexpr std::uint32_t kMaxOracleReserveCount = 2; constexpr std::size_t kOracleReserveCountThreshold = 5; -inline uint32_t +inline std::uint32_t calculateOracleReserve(std::size_t priceDataSeriesCount) { return priceDataSeriesCount > kOracleReserveCountThreshold ? kMaxOracleReserveCount diff --git a/include/xrpl/ledger/helpers/SponsorHelpers.h b/include/xrpl/ledger/helpers/SponsorHelpers.h index 1b8d877493..8ebeed3b6b 100644 --- a/include/xrpl/ledger/helpers/SponsorHelpers.h +++ b/include/xrpl/ledger/helpers/SponsorHelpers.h @@ -1,12 +1,8 @@ #pragma once -#include #include #include -#include #include -#include -#include #include #include #include @@ -64,7 +60,7 @@ isReserveSponsored(STTx const& tx) } std::optional -getTxReserveSponsorAccountID(STTx const& tx); +getTxReserveSponsorID(STTx const& tx); std::expected getTxReserveSponsor(ApplyViewContext ctx); @@ -89,7 +85,7 @@ getTxReserveSponsor(ReadView const& view, STTx const& tx); getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::const_ref accountSle); std::optional -getLedgerEntryReserveSponsorAccountID(SLE::const_ref sle, SF_ACCOUNT const& field = sfSponsor); +getLedgerEntryReserveSponsorID(SLE::const_ref sle, SF_ACCOUNT const& field = sfSponsor); SLE::pointer getLedgerEntryReserveSponsor( @@ -123,130 +119,16 @@ addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::ref sle, SF_ACCOUNT const& fi void removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field = sfSponsor); -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::signerList(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; - }; -} +std::optional +getLedgerEntryOwner(ReadView const& view, SLE const& sle, AccountID const& account); -template -inline bool -isLedgerEntrySupportedBySponsorship(T const& sle) -{ - switch (sle->getType()) - { - case ltCHECK: - case ltESCROW: - case ltPAYCHAN: - case ltMPTOKEN: - case ltDELEGATE: - case ltDEPOSIT_PREAUTH: - case ltMPTOKEN_ISSUANCE: - case ltSIGNER_LIST: - case ltCREDENTIAL: - case ltRIPPLE_STATE: - return true; - default: - return false; - }; -} +bool +isLedgerEntrySupportedBySponsorship(SLE const& sle); -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; - case ltSIGNER_LIST: { - // Mirror SignerListSet's owner-count accounting so that create and - // delete agree. Modern lists (post-MultiSignReserve) carry the - // lsfOneOwnerCount flag and cost a single owner count. Legacy - // pre-MultiSignReserve lists cost 2 + signer_count owner counts - if (sle->isFlag(lsfOneOwnerCount)) - return 1; - return 2 + static_cast(sle->getFieldArray(sfSignerEntries).size()); - } - default: - return 1; - } -}; +std::uint32_t +getLedgerEntryOwnerCount(SLE const& sle); -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; - } -}; +SF_ACCOUNT const& +getLedgerEntrySponsorField(SLE const& sle, AccountID const& owner); } // namespace xrpl diff --git a/include/xrpl/tx/invariants/SponsorshipInvariant.h b/include/xrpl/tx/invariants/SponsorshipInvariant.h index 529a8dadeb..c67111459f 100644 --- a/include/xrpl/tx/invariants/SponsorshipInvariant.h +++ b/include/xrpl/tx/invariants/SponsorshipInvariant.h @@ -8,7 +8,6 @@ #include #include -#include namespace xrpl { @@ -29,7 +28,7 @@ class SponsorshipOwnerCountsMatch public: void - visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); + visitEntry(bool, SLE::const_ref, SLE::const_ref); [[nodiscard]] bool finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; @@ -50,7 +49,7 @@ class SponsorshipAccountCountMatchesField public: void - visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); + visitEntry(bool, SLE::const_ref, SLE::const_ref); [[nodiscard]] bool finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp index 835a0b640a..f0be1fb129 100644 --- a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -369,6 +369,9 @@ checkReserve( return tefINTERNAL; // LCOV_EXCL_LINE if (sponsorSle) { + if (sponsorSle->getType() != ltACCOUNT_ROOT) + return tefINTERNAL; // LCOV_EXCL_LINE + auto const sle = ctx.view.read( keylet::sponsorship( sponsorSle->getAccountID(sfAccount), accSle->getAccountID(sfAccount))); diff --git a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp index d153bee54a..577d7c15b8 100644 --- a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp +++ b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp @@ -142,7 +142,7 @@ addEmptyHolding( if (accountID == mptIssue.getIssuer()) return tesSUCCESS; - return authorizeMPToken(ctx, priorBalance, mptID, accountID, journal, 0, std::nullopt); + return authorizeMPToken(ctx, priorBalance, mptID, accountID, journal); } [[nodiscard]] TER diff --git a/src/libxrpl/ledger/helpers/SponsorHelpers.cpp b/src/libxrpl/ledger/helpers/SponsorHelpers.cpp index 8c1a6fc436..dcaf2fb896 100644 --- a/src/libxrpl/ledger/helpers/SponsorHelpers.cpp +++ b/src/libxrpl/ledger/helpers/SponsorHelpers.cpp @@ -4,21 +4,24 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include +#include #include #include namespace xrpl { std::optional -getTxReserveSponsorAccountID(STTx const& tx) +getTxReserveSponsorID(STTx const& tx) { if (tx.isFieldPresent(sfSponsor) && isReserveSponsored(tx)) { @@ -30,7 +33,7 @@ getTxReserveSponsorAccountID(STTx const& tx) std::expected getTxReserveSponsor(ApplyViewContext ctx) { - auto const sponsorID = getTxReserveSponsorAccountID(ctx.tx); + auto const sponsorID = getTxReserveSponsorID(ctx.tx); if (sponsorID) { auto sle = ctx.view.peek(keylet::account(*sponsorID)); @@ -46,7 +49,7 @@ getTxReserveSponsor(ApplyViewContext ctx) std::expected getTxReserveSponsor(ReadView const& view, STTx const& tx) { - auto const sponsorID = getTxReserveSponsorAccountID(tx); + auto const sponsorID = getTxReserveSponsorID(tx); if (sponsorID) { auto sle = view.read(keylet::account(*sponsorID)); @@ -69,7 +72,7 @@ getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::const_ref accountSle) } std::optional -getLedgerEntryReserveSponsorAccountID(SLE::const_ref sle, SF_ACCOUNT const& field) +getLedgerEntryReserveSponsorID(SLE::const_ref sle, SF_ACCOUNT const& field) { if (sle->isFieldPresent(field)) return sle->getAccountID(field); @@ -79,7 +82,7 @@ getLedgerEntryReserveSponsorAccountID(SLE::const_ref sle, SF_ACCOUNT const& fiel SLE::pointer getLedgerEntryReserveSponsor(ApplyView& view, SLE::const_ref sle, SF_ACCOUNT const& field) { - auto const sponsorID = getLedgerEntryReserveSponsorAccountID(sle, field); + auto const sponsorID = getLedgerEntryReserveSponsorID(sle, field); if (sponsorID) return view.peek(keylet::account(*sponsorID)); return {}; @@ -88,7 +91,7 @@ getLedgerEntryReserveSponsor(ApplyView& view, SLE::const_ref sle, SF_ACCOUNT con SLE::const_pointer getLedgerEntryReserveSponsor(ReadView const& view, SLE::const_ref sle, SF_ACCOUNT const& field) { - auto const sponsorID = getLedgerEntryReserveSponsorAccountID(sle, field); + auto const sponsorID = getLedgerEntryReserveSponsorID(sle, field); if (sponsorID) return view.read(keylet::account(*sponsorID)); return {}; @@ -127,4 +130,126 @@ removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field) sle->makeFieldAbsent(field); } +std::optional +getLedgerEntryOwner(ReadView const& view, SLE 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::signerList(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("xrpl::getLedgerEntryOwner : object is not supported by sponsorship."); + return std::nullopt; + }; +} + +bool +isLedgerEntrySupportedBySponsorship(SLE const& sle) +{ + switch (sle.getType()) + { + case ltCHECK: + case ltESCROW: + case ltPAYCHAN: + case ltMPTOKEN: + case ltDELEGATE: + case ltDEPOSIT_PREAUTH: + case ltMPTOKEN_ISSUANCE: + case ltSIGNER_LIST: + case ltCREDENTIAL: + case ltRIPPLE_STATE: + return true; + default: + return false; + }; +} + +std::uint32_t +getLedgerEntryOwnerCount(SLE 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; + case ltSIGNER_LIST: { + // Mirror SignerListSet's owner-count accounting so that create and + // delete agree. Modern lists (post-MultiSignReserve) carry the + // lsfOneOwnerCount flag and cost a single owner count. Legacy + // pre-MultiSignReserve lists cost 2 + signer_count owner counts + if (sle.isFlag(lsfOneOwnerCount)) + return 1; + return 2 + static_cast(sle.getFieldArray(sfSignerEntries).size()); + } + default: + return 1; + } +} + +SF_ACCOUNT const& +getLedgerEntrySponsorField(SLE 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("xrpl::getLedgerEntrySponsorField : unknown owner for RippleState"); + return sfSponsor; + // LCOV_EXCL_STOP + } + default: + return sfSponsor; + } +} + } // namespace xrpl diff --git a/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp b/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp index e40bde8d48..b855f88df2 100644 --- a/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp +++ b/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp @@ -13,36 +13,31 @@ #include #include -#include namespace xrpl { // Add new sponsorship-related invariants implementations void -SponsorshipOwnerCountsMatch::visitEntry( - bool isDelete, - std::shared_ptr const& before, - std::shared_ptr const& after) +SponsorshipOwnerCountsMatch::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) { - auto getSponsored = [](std::shared_ptr const& sle) -> std::uint32_t { + auto getSponsored = [](SLE::const_ref sle) -> std::uint32_t { if (sle && sle->getType() == ltACCOUNT_ROOT) return sle->getFieldU32(sfSponsoredOwnerCount); return 0; }; - auto getSponsoring = [](std::shared_ptr const& sle) -> std::uint32_t { + auto getSponsoring = [](SLE::const_ref sle) -> std::uint32_t { if (sle && sle->getType() == ltACCOUNT_ROOT) return sle->getFieldU32(sfSponsoringOwnerCount); return 0; }; - auto getOwnerCount = [](std::shared_ptr const& sle) -> std::uint32_t { + auto getOwnerCount = [](SLE::const_ref sle) -> std::uint32_t { if (sle && sle->getType() == ltACCOUNT_ROOT) return sle->getFieldU32(sfOwnerCount); return 0; }; - auto getSponsoredObjectOwnerCount = - [&](std::shared_ptr const& sle) -> std::uint32_t { + auto getSponsoredObjectOwnerCount = [&](SLE::const_ref sle) -> std::uint32_t { if (!sle) return 0; switch (sle->getType()) @@ -138,18 +133,15 @@ SponsorshipOwnerCountsMatch::finalize( } void -SponsorshipAccountCountMatchesField::visitEntry( - bool, - std::shared_ptr const& before, - std::shared_ptr const& after) +SponsorshipAccountCountMatchesField::visitEntry(bool, SLE::const_ref before, SLE::const_ref after) { - auto getSponsoringAccountCount = [](std::shared_ptr const& sle) -> std::uint32_t { + auto getSponsoringAccountCount = [](SLE::const_ref sle) -> std::uint32_t { if (sle && sle->getType() == ltACCOUNT_ROOT) return sle->getFieldU32(sfSponsoringAccountCount); return 0; }; - auto hasSponsorField = [](std::shared_ptr const& sle) -> bool { + auto hasSponsorField = [](SLE::const_ref sle) -> bool { return sle && sle->getType() == ltACCOUNT_ROOT && sle->isFieldPresent(sfSponsor); }; diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp index 1163e2bcf0..50f2e8b859 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp @@ -460,10 +460,7 @@ EscrowCreate::doApply() // source only owes reserve for its current owners. // - unsponsored: 1 — source owes reserve including the new increment. auto const sourceReserve = accountReserve( - ctx_.view(), - sle, - j_, - {.ownerCountDelta = getTxReserveSponsorAccountID(ctx_.tx) ? 0 : 1}); + ctx_.view(), sle, j_, {.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1}); if (balance - STAmount(amount).xrp() < sourceReserve) return tecUNFUNDED; } diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp index 006131a2ec..b17430948a 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp @@ -158,10 +158,7 @@ PaymentChannelCreate::doApply() // the source only owes reserve for its current owners. // - unsponsored: 1 — source owes reserve including the new increment. auto const sourceReserve = accountReserve( - ctx_.view(), - sle, - j_, - {.ownerCountDelta = getTxReserveSponsorAccountID(ctx_.tx) ? 0 : 1}); + ctx_.view(), sle, j_, {.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1}); if (preFeeBalance_ - ctx_.tx[sfAmount].xrp() < sourceReserve) return tecUNFUNDED; } diff --git a/src/libxrpl/tx/transactors/sponsor/SponsorshipSet.cpp b/src/libxrpl/tx/transactors/sponsor/SponsorshipSet.cpp index 9913fb0cfc..547107ebd3 100644 --- a/src/libxrpl/tx/transactors/sponsor/SponsorshipSet.cpp +++ b/src/libxrpl/tx/transactors/sponsor/SponsorshipSet.cpp @@ -370,10 +370,7 @@ SponsorshipSet::doApply() } void -SponsorshipSet::visitInvariantEntry( - bool, - std::shared_ptr const&, - std::shared_ptr const&) +SponsorshipSet::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) { } diff --git a/src/libxrpl/tx/transactors/sponsor/SponsorshipTransfer.cpp b/src/libxrpl/tx/transactors/sponsor/SponsorshipTransfer.cpp index 2e4dfec822..03bf00f9d0 100644 --- a/src/libxrpl/tx/transactors/sponsor/SponsorshipTransfer.cpp +++ b/src/libxrpl/tx/transactors/sponsor/SponsorshipTransfer.cpp @@ -195,7 +195,7 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx) // sponsorship may use pre-funded reserve sponsorship instead. bool const isCreateOrReassign = ctx.tx.isFlag(tfSponsorshipCreate) || ctx.tx.isFlag(tfSponsorshipReassign); - auto const reserveSponsor = getTxReserveSponsorAccountID(ctx.tx); + auto const reserveSponsor = getTxReserveSponsorID(ctx.tx); bool const isAccountReserveSponsorship = isCreateOrReassign && reserveSponsor && !ctx.tx.isFieldPresent(sfObjectID); @@ -244,10 +244,10 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx) if (!objectSle) return tecNO_ENTRY; - if (!isLedgerEntrySupportedBySponsorship(objectSle)) + if (!isLedgerEntrySupportedBySponsorship(*objectSle)) return tecNO_PERMISSION; - auto const owner = getLedgerEntryOwner(ctx.view, objectSle, sponseeID); + auto const owner = getLedgerEntryOwner(ctx.view, *objectSle, sponseeID); if (!owner.has_value() || owner.value() != sponseeID) return tecNO_PERMISSION; @@ -255,7 +255,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx) // depends on the object type, a RippleState stores the sponsor in // sfHighSponsor/sfLowSponsor, while other object type uses sfSponsor. targetSle = objectSle; - sponsorField = &getLedgerEntrySponsorField(objectSle, owner.value()); + sponsorField = &getLedgerEntrySponsorField(*objectSle, owner.value()); } bool const isSponsored = targetSle->isFieldPresent(*sponsorField); @@ -315,7 +315,7 @@ SponsorshipTransfer::doApply() if (!objectSle) return tefINTERNAL; // LCOV_EXCL_LINE - auto const ownerID = getLedgerEntryOwner(view(), objectSle, sponseeID); + auto const ownerID = getLedgerEntryOwner(view(), *objectSle, sponseeID); if (!ownerID) return tefINTERNAL; // LCOV_EXCL_LINE @@ -323,8 +323,9 @@ SponsorshipTransfer::doApply() if (!ownerSle) return tefINTERNAL; // LCOV_EXCL_LINE - auto const ownerCountDelta = static_cast(getLedgerEntryOwnerCount(objectSle)); - auto const& sponsorField = getLedgerEntrySponsorField(objectSle, *ownerID); + auto const ownerCountDelta = + static_cast(getLedgerEntryOwnerCount(*objectSle)); + auto const& sponsorField = getLedgerEntrySponsorField(*objectSle, *ownerID); if (isCreate || isReassign) { @@ -526,10 +527,7 @@ SponsorshipTransfer::doApply() } void -SponsorshipTransfer::visitInvariantEntry( - bool, - std::shared_ptr const&, - std::shared_ptr const&) +SponsorshipTransfer::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) { }