diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index 6815f266f4..e0c095b263 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -118,19 +118,12 @@ public: env(sponsor::set(sponsor, sponsor, 0), ter(temMALFORMED)); // Invalid feeAmount - env(sponsor::set_fee( - sponsor, alice, tfSponsorshipClearRequireSignForFee, XRP(1)), - ter(temMALFORMED)); - for (auto amt : {XRP(-1), XRP(0), USD(1)}) { env(sponsor::set_fee(sponsor, alice, 0, amt), ter(temBAD_AMOUNT)); } // Invalid reserveCount - env(sponsor::set_reserve( - sponsor, alice, tfSponsorshipClearRequireSignForReserve, 1), - ter(temMALFORMED)); env(sponsor::set_reserve(sponsor, alice, 0, 0), ter(temMALFORMED)); // Invalid Delete operation @@ -686,6 +679,38 @@ public: sponsorFeeBalance(sponsor, alice) == sponsorFee - feeAmt); } } + + // test lsfSponsorshipRequireSignForFee + { + Env env{*this, testable_amendments()}; + Account const alice("alice"); + Account const bob("bob"); + Account const sponsor("sponsor"); + env.fund(XRP(10000), alice, bob, sponsor); + env.close(); + + // set flag + env(sponsor::set_fee( + sponsor, alice, tfSponsorshipSetRequireSignForFee, XRP(10))); + env.close(); + + env(pay(alice, bob, XRP(100)), + fee(XRP(10)), + sponsor::as(sponsor, tfSponsorFee), + ter(terNO_SPONSORSHIP)); + env.close(); + + // clear flag + env(sponsor::set_fee( + sponsor, alice, tfSponsorshipClearRequireSignForFee, XRP(10))); + env.close(); + + env(pay(alice, bob, XRP(100)), + fee(XRP(10)), + sponsor::as(sponsor, tfSponsorFee), + ter(tesSUCCESS)); + env.close(); + } } void @@ -741,6 +766,42 @@ public: } } + void + testRequireFlag() + { + testcase("SponsorshipRequireSignForReserve"); + using namespace test::jtx; + + Env env{*this, testable_amendments()}; + Account const alice("alice"); + Account const bob("bob"); + Account const sponsor("sponsor"); + env.fund(XRP(10000), alice, bob, sponsor); + env.close(); + + // set flag + env(sponsor::set_reserve( + sponsor, alice, tfSponsorshipSetRequireSignForReserve, 10)); + env.close(); + + env(check::create(alice, bob, XRP(100)), + fee(XRP(10)), + sponsor::as(sponsor, tfSponsorReserve), + ter(terNO_SPONSORSHIP)); + env.close(); + + // clear flag + env(sponsor::set_reserve( + sponsor, alice, tfSponsorshipClearRequireSignForReserve, 1)); + env.close(); + + env(check::create(alice, bob, XRP(100)), + fee(XRP(10)), + sponsor::as(sponsor, tfSponsorReserve), + ter(tesSUCCESS)); + env.close(); + } + void testCheck() { @@ -1269,6 +1330,7 @@ public: void testSponsorReserve() { + testRequireFlag(); testCheck(); testOfffer(); testTicket(); diff --git a/src/xrpld/app/tx/detail/SponsorshipSet.cpp b/src/xrpld/app/tx/detail/SponsorshipSet.cpp index 2725578984..5724d380f1 100644 --- a/src/xrpld/app/tx/detail/SponsorshipSet.cpp +++ b/src/xrpld/app/tx/detail/SponsorshipSet.cpp @@ -82,9 +82,6 @@ SponsorshipSet::preflight(PreflightContext const& ctx) if (ctx.tx.isFieldPresent(sfFeeAmount)) { - if (ctx.tx.getFlags() & tfSponsorshipClearRequireSignForFee) - return temMALFORMED; - auto const feeAmount = ctx.tx.getFieldAmount(sfFeeAmount); if (!isXRP(feeAmount)) @@ -108,9 +105,6 @@ SponsorshipSet::preflight(PreflightContext const& ctx) if (ctx.tx.isFieldPresent(sfReserveCount)) { - if (ctx.tx.getFlags() & tfSponsorshipClearRequireSignForReserve) - return temMALFORMED; - auto const reserveCount = ctx.tx.getFieldU32(sfReserveCount); // TODO: max reserveCount? if (reserveCount < 1) @@ -158,12 +152,13 @@ TER SponsorshipSet::doApply() { auto const sponseeAcc = ctx_.tx[sfSponsee]; - auto const keylet = keylet::sponsor(account_, sponseeAcc); auto const sponsorAcc = ctx_.tx.isFieldPresent(sfSponsorAccount) ? ctx_.tx.getAccountID(sfSponsorAccount) : account_; + auto const keylet = keylet::sponsor(sponsorAcc, sponseeAcc); + auto const sponsorAccSle = ctx_.view().peek(keylet::account(sponsorAcc)); if (!sponsorAccSle) return tecINTERNAL; @@ -222,7 +217,6 @@ SponsorshipSet::doApply() (*newSle)[sfOwner] = sponsorAcc; (*newSle)[sfSponsee] = sponseeAcc; - (*newSle)[sfFlags] = ctx_.tx.getFlags(); if (feeAmount) { (*sponsorAccSle)[sfBalance] -= *feeAmount; @@ -237,6 +231,15 @@ SponsorshipSet::doApply() (*newSle)[sfReserveCount] = *reserveCount; } + auto flags = 0; + if (ctx_.tx.isFlag(tfSponsorshipSetRequireSignForFee)) + flags |= lsfSponsorshipRequireSignForFee; + + if (ctx_.tx.isFlag(tfSponsorshipSetRequireSignForReserve)) + flags |= lsfSponsorshipRequireSignForReserve; + + (*newSle)[sfFlags] = flags; + auto const sponsorPage = view().dirInsert( keylet::ownerDir(sponsorAcc), keylet, describeOwnerDir(sponsorAcc)); (*newSle)[sfOwnerNode] = *sponsorPage; diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index dd0f6ea9f8..ac6ce1c32b 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -259,35 +259,26 @@ Transactor::checkSponsor(ReadView const& view, STTx const& tx) auto const sponsorAcc = txSponsor.getAccountID(sfAccount); auto const sponseeAcc = tx.getAccountID(sfAccount); - auto const hasSignature = txSponsor.isFieldPresent(sfTxnSignature) || + auto const hasSponsorSignature = txSponsor.isFieldPresent(sfTxnSignature) || !txSponsor.getFieldVL(sfSigningPubKey).empty() || txSponsor.isFieldPresent(sfSigners); - auto const sponsorSle = view.read(keylet::sponsor(sponsorAcc, sponseeAcc)); - if (!hasSignature) + if (!hasSponsorSignature) { + auto const sponsorSle = + view.read(keylet::sponsor(sponsorAcc, sponseeAcc)); + // pre funded if (!sponsorSle) - return tecNO_SPONSOR_PERMISSION; - } - else - { - // co-signed - if (!sponsorSle) - return tesSUCCESS; + return terNO_SPONSORSHIP; if (txSponsor.isFlag(tfSponsorFee) && sponsorSle->isFlag(lsfSponsorshipRequireSignForFee)) - { - if (!hasSignature) - return tecNO_SPONSOR_PERMISSION; - } + return terNO_SPONSORSHIP; + if (txSponsor.isFlag(tfSponsorReserve) && sponsorSle->isFlag(lsfSponsorshipRequireSignForReserve)) - { - if (!hasSignature) - return tecNO_SPONSOR_PERMISSION; - } + return terNO_SPONSORSHIP; } return tesSUCCESS;