diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index a664cc5e94..2b2afb4096 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -280,6 +280,7 @@ constexpr std::uint32_t tfSponsorshipSetRequireSignForReserve = 0 constexpr std::uint32_t tfSponsorshipClearRequireSignForReserve = 0x00080000; constexpr std::uint32_t tfDeleteObject = 0x00100000; constexpr std::uint32_t tfSponsorshipSetMask = ~(tfUniversal | tfSponsorshipSetRequireSignForFee | tfSponsorshipClearRequireSignForFee | tfSponsorshipSetRequireSignForReserve | tfSponsorshipClearRequireSignForReserve | tfDeleteObject); +constexpr std::uint32_t tfSponsorshipSetPermissionMask = ~(tfUniversal | tfSponsorshipSetRequireSignForFee | tfSponsorshipSetRequireSignForReserve ); // clang-format on diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index 0ec470611f..9217b41f64 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -1222,54 +1222,51 @@ adjustOwnerCount( if (sponsorSle) { - XRPL_ASSERT(sponsorSle, "ripple::adjustOwnerCount : sponsor not found"); + XRPL_ASSERT(sponsorSle, "ripple::adjustOwnerCount : sponsor exists"); + auto const account = accountSle->getAccountID(sfAccount); + auto const sponsorAcc = (*sponsorSle)->getAccountID(sfAccount); { // modify sponsor's SponsoringOwnerCount std::uint32_t const current{ (*sponsorSle)->getFieldU32(sfSponsoringOwnerCount)}; - AccountID const id = (*sponsorSle)->getAccountID(sfAccount); std::uint32_t const adjusted = - confineOwnerCount(current, amount, id, j); - view.adjustOwnerCountHook(id, current, adjusted); + confineOwnerCount(current, amount, sponsorAcc, j); + view.adjustOwnerCountHook(sponsorAcc, current, adjusted); if (adjusted == 0) (*sponsorSle)->makeFieldAbsent(sfSponsoringOwnerCount); else - (*sponsorSle)->at(sfSponsoringOwnerCount) = adjusted; + (*sponsorSle)->setFieldU32(sfSponsoringOwnerCount, adjusted); view.update(*sponsorSle); } { // modify account's SponsoredOwnerCount std::uint32_t const current{ accountSle->getFieldU32(sfSponsoredOwnerCount)}; - AccountID const id = (*accountSle)[sfAccount]; std::uint32_t const adjusted = - confineOwnerCount(current, amount, id, j); - view.adjustOwnerCountHook(id, current, adjusted); + confineOwnerCount(current, amount, account, j); + view.adjustOwnerCountHook(account, current, adjusted); if (adjusted == 0) accountSle->makeFieldAbsent(sfSponsoredOwnerCount); else - accountSle->at(sfSponsoredOwnerCount) = adjusted; + accountSle->setFieldU32(sfSponsoredOwnerCount, adjusted); view.update(accountSle); } - auto sle = view.peek(keylet::sponsor( - (*sponsorSle)->getAccountID(sfAccount), - accountSle->getAccountID(sfAccount))); + auto sle = view.peek(keylet::sponsor(sponsorAcc, account)); if (sle && amount > 0) { // pre funded - // modify sponsor's ReserveCount - + // update the pre-funded ReserveCount on Sponsorship ledger object XRPL_ASSERT( - sle, "ripple::adjustOwnerCount : co-signing sponsor not found"); + sle, "ripple::adjustOwnerCount : co-signing sponsor exists"); auto const currentReserveCount = sle->getFieldU32(sfReserveCount); XRPL_ASSERT( currentReserveCount >= amount, - "ripple::adjustOwnerCount : reserve count not enough"); + "ripple::adjustOwnerCount : enough reserve count"); - sle->at(sfReserveCount) = currentReserveCount - amount; + sle->setFieldU32(sfReserveCount, currentReserveCount - amount); view.update(sle); } } diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index 8aca80c9df..88143ed43d 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -183,6 +183,11 @@ public: sponsor::sponseeAcc(noFunded), ter(tecNO_DST)); + // Invalid Sponsor + env(sponsor::set(sponsor, tfDeleteObject), + sponsor::sponsorAcc(noFunded), + ter(tecNO_DST)); + // Invalid Delete operation (sponsorship not found) env(sponsor::set(sponsor, tfDeleteObject), sponsor::sponseeAcc(alice), diff --git a/src/xrpld/app/tx/detail/SponsorshipSet.cpp b/src/xrpld/app/tx/detail/SponsorshipSet.cpp index ea92947d09..b0908b2b81 100644 --- a/src/xrpld/app/tx/detail/SponsorshipSet.cpp +++ b/src/xrpld/app/tx/detail/SponsorshipSet.cpp @@ -15,9 +15,8 @@ SponsorshipSet::getFlagsMask(PreflightContext const& ctx) NotTEC SponsorshipSet::preflight(PreflightContext const& ctx) { - // check Flags + auto const flags = ctx.tx.getFlags(); { - auto const flags = ctx.tx.getFlags(); if ((flags & tfSponsorshipSetRequireSignForFee) && (flags & tfSponsorshipClearRequireSignForFee)) return temINVALID_FLAG; @@ -39,8 +38,8 @@ SponsorshipSet::preflight(PreflightContext const& ctx) } auto const account = ctx.tx.getAccountID(sfAccount); - bool hasSponsor = ctx.tx.isFieldPresent(sfSponsorAccount); - bool hasSponsee = ctx.tx.isFieldPresent(sfSponsee); + bool const hasSponsor = ctx.tx.isFieldPresent(sfSponsorAccount); + bool const hasSponsee = ctx.tx.isFieldPresent(sfSponsee); // The transaction must specify either Sponsor or Sponsee, but not both. if (hasSponsor == hasSponsee) @@ -52,7 +51,6 @@ SponsorshipSet::preflight(PreflightContext const& ctx) if (sponsor == sponsee) return temMALFORMED; - auto const flags = ctx.tx.getFlags(); if (flags & tfDeleteObject) { // can not combine with any modification flags when deleting @@ -139,14 +137,21 @@ SponsorshipSet::checkPermission(ReadView const& view, STTx const& tx) if (checkTxPermission(sle, tx) == tesSUCCESS) return tesSUCCESS; + auto const txFlags = tx.getFlags(); + + // this is added in case more flags will be added for SponsorshipSet + // in the future. Currently unreachable. + if (txFlags & tfSponsorshipSetPermissionMask) + return terNO_DELEGATE_PERMISSION; + std::unordered_set granularPermissions; loadGranularPermission(sle, ttSPONSORSHIP_SET, granularPermissions); auto const sponsoringFee = tx.isFieldPresent(sfFeeAmount) || tx.isFieldPresent(sfMaxFee) || - tx.isFlag(tfSponsorshipSetRequireSignForFee); + txFlags & tfSponsorshipSetRequireSignForFee; auto const sponsoringReserve = tx.isFieldPresent(sfReserveCount) || - tx.isFlag(tfSponsorshipSetRequireSignForReserve); + txFlags & tfSponsorshipSetRequireSignForReserve; if (sponsoringFee && !granularPermissions.contains(SponsorFee)) return terNO_DELEGATE_PERMISSION; @@ -160,16 +165,16 @@ SponsorshipSet::checkPermission(ReadView const& view, STTx const& tx) TER SponsorshipSet::preclaim(PreclaimContext const& ctx) { - auto const sponsor = ctx.tx.isFieldPresent(sfSponsorAccount) - ? ctx.tx.getAccountID(sfSponsorAccount) - : ctx.tx.getAccountID(sfAccount); - auto const sponsee = ctx.tx.isFieldPresent(sfSponsee) - ? ctx.tx.getAccountID(sfSponsee) - : ctx.tx.getAccountID(sfAccount); + auto const sponsor = ctx.tx[~sfSponsorAccount].value_or(ctx.tx[sfAccount]); + auto const sponsee = ctx.tx[~sfSponsee].value_or(ctx.tx[sfAccount]); if (sponsee == sponsor) return tecINTERNAL; // LCOV_EXCL_LINE + // check Sponsor + if (!ctx.view.exists(keylet::account(sponsor))) + return tecNO_DST; + // check Sponsee auto const sponseeSle = ctx.view.read(keylet::account(sponsee)); if (!sponseeSle) @@ -191,24 +196,21 @@ SponsorshipSet::preclaim(PreclaimContext const& ctx) TER SponsorshipSet::doApply() { - auto const sponseeAcc = ctx_.tx.isFieldPresent(sfSponsee) - ? ctx_.tx.getAccountID(sfSponsee) - : ctx_.tx.getAccountID(sfAccount); - - auto const sponsorAcc = ctx_.tx.isFieldPresent(sfSponsorAccount) - ? ctx_.tx.getAccountID(sfSponsorAccount) - : account_; + auto const sponsorAcc = ctx_.tx[~sfSponsorAccount].value_or(account_); + auto const sponseeAcc = ctx_.tx[~sfSponsee].value_or(account_); if (sponseeAcc == sponsorAcc) return tecINTERNAL; // LCOV_EXCL_LINE - auto const keylet = keylet::sponsor(sponsorAcc, sponseeAcc); - auto const sponsorAccSle = ctx_.view().peek(keylet::account(sponsorAcc)); if (!sponsorAccSle) return tecINTERNAL; // LCOV_EXCL_LINE - auto const sponsorObjSle = ctx_.view().peek(keylet); + if (!ctx_.view().exists(keylet::account(sponseeAcc))) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const sponsorKeylet = keylet::sponsor(sponsorAcc, sponseeAcc); + auto const sponsorObjSle = ctx_.view().peek(sponsorKeylet); if (ctx_.tx.isFlag(tfDeleteObject)) { @@ -249,7 +251,7 @@ SponsorshipSet::doApply() if (!sponsorObjSle) { // Create - auto newSle = std::make_shared(keylet); + auto newSle = std::make_shared(sponsorKeylet); if (auto const ret = checkInsufficientReserve( ctx_.view(), @@ -287,11 +289,15 @@ SponsorshipSet::doApply() (*newSle)[sfFlags] = flags; auto const sponsorPage = view().dirInsert( - keylet::ownerDir(sponsorAcc), keylet, describeOwnerDir(sponsorAcc)); + keylet::ownerDir(sponsorAcc), + sponsorKeylet, + describeOwnerDir(sponsorAcc)); (*newSle)[sfOwnerNode] = *sponsorPage; auto const sponseePage = view().dirInsert( - keylet::ownerDir(sponseeAcc), keylet, describeOwnerDir(sponseeAcc)); + keylet::ownerDir(sponseeAcc), + sponsorKeylet, + describeOwnerDir(sponseeAcc)); (*newSle)[sfSponseeNode] = *sponseePage; auto viewJ = ctx_.app.journal("View");