From fed56b2eebc2bee659962eecb0ac5332ae28d678 Mon Sep 17 00:00:00 2001 From: tequ Date: Sat, 20 Sep 2025 14:29:33 +0900 Subject: [PATCH] address SponsorAccount/Sponsee field changes --- .../xrpl/protocol/detail/transactions.macro | 2 +- src/test/app/Sponsor_test.cpp | 157 +++++++++++++----- src/test/jtx/impl/sponsor.cpp | 20 +-- src/test/jtx/sponsor.h | 20 ++- src/test/rpc/AccountObjects_test.cpp | 12 +- src/test/rpc/AccountTx_test.cpp | 4 +- src/xrpld/app/tx/detail/SponsorshipSet.cpp | 47 ++++-- 7 files changed, 181 insertions(+), 81 deletions(-) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index b66f09f684..f7135fe919 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -534,7 +534,7 @@ TRANSACTION(ttSPONSORSHIP_TRANSFER, 72, SponsorshipTransfer, Delegation::notDele /** This transaction create sponsorship object */ TRANSACTION(ttSPONSORSHIP_SET, 73, SponsorshipSet, Delegation::notDelegatable, ({ {sfSponsorAccount, soeOPTIONAL}, - {sfSponsee, soeREQUIRED}, + {sfSponsee, soeOPTIONAL}, {sfFeeAmount, soeOPTIONAL}, {sfMaxFee, soeOPTIONAL}, {sfReserveCount, soeOPTIONAL}, diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index 04478744e0..7f07071c13 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -45,7 +45,7 @@ public: ter(temDISABLED)); env(sponsor::transfer(alice), ter(temDISABLED)); - env(sponsor::set(sponsor, alice, 0), ter(temDISABLED)); + env(sponsor::set(sponsor, 0), ter(temDISABLED)); } void @@ -70,22 +70,22 @@ public: // Invalid flags { - env(sponsor::set( - sponsor, alice, ~tfSponsorshipSetMask - tfInnerBatchTxn), + env(sponsor::set(sponsor, ~tfSponsorshipSetMask - tfInnerBatchTxn), + sponsor::sponseeAcc(alice), ter(temINVALID_FLAG)); env(sponsor::set( sponsor, - alice, tfSponsorshipSetRequireSignForFee | tfSponsorshipClearRequireSignForFee), + sponsor::sponseeAcc(alice), ter(temINVALID_FLAG)); env(sponsor::set( sponsor, - alice, tfSponsorshipSetRequireSignForReserve | tfSponsorshipClearRequireSignForReserve), + sponsor::sponseeAcc(alice), ter(temINVALID_FLAG)); for (auto flag : @@ -94,38 +94,46 @@ public: tfSponsorshipSetRequireSignForReserve, tfSponsorshipClearRequireSignForReserve}) { - env(sponsor::set(sponsor, alice, tfDeleteObject | flag), + env(sponsor::set(sponsor, tfDeleteObject | flag), + sponsor::sponseeAcc(alice), ter(temINVALID_FLAG)); } } - // invalid SponsorAccount - env(sponsor::set(alice, sponsor, tfDeleteObject), + // invalid SponsorAccount / Sponsee + // Account = Sponsor + env(sponsor::set(alice, tfDeleteObject), sponsor::sponsorAcc(alice), ter(temMALFORMED)); - env(sponsor::set(alice, sponsor, tfDeleteObject), - sponsor::sponsorAcc(bob), + // Account = Sponsee + env(sponsor::set(alice, tfDeleteObject), + sponsor::sponseeAcc(alice), ter(temMALFORMED)); - env(sponsor::set(alice, alice, 0), + // Both Sponsor and Sponsee are specified + env(sponsor::set(alice, 0), sponsor::sponsorAcc(sponsor), + sponsor::sponseeAcc(alice), ter(temMALFORMED)); - // Invalid Sponsee - env(sponsor::set(sponsor, sponsor, 0), ter(temMALFORMED)); - // Invalid feeAmount for (auto amt : {XRP(-1), XRP(0), USD(1)}) { - env(sponsor::set_fee(sponsor, alice, 0, amt), ter(temBAD_AMOUNT)); + env(sponsor::set_fee(sponsor, 0, amt), + sponsor::sponseeAcc(alice), + ter(temBAD_AMOUNT)); } // Invalid reserveCount - env(sponsor::set_reserve(sponsor, alice, 0, 0), ter(temMALFORMED)); + env(sponsor::set_reserve(sponsor, 0, 0), + sponsor::sponseeAcc(alice), + ter(temMALFORMED)); // Invalid Delete operation - env(sponsor::set_reserve(sponsor, alice, tfDeleteObject, 1), + env(sponsor::set_reserve(sponsor, tfDeleteObject, 1), + sponsor::sponseeAcc(alice), ter(temMALFORMED)); - env(sponsor::set_fee(sponsor, alice, tfDeleteObject, XRP(1)), + env(sponsor::set_fee(sponsor, tfDeleteObject, XRP(1)), + sponsor::sponseeAcc(alice), ter(temMALFORMED)); // TODO: test MaxFee with tfDeleteObject @@ -134,15 +142,21 @@ public: // // Invalid Sponsee - env(sponsor::set(sponsor, noFunded, 0), ter(tecNO_DST)); + env(sponsor::set(sponsor, 0), + sponsor::sponseeAcc(noFunded), + ter(tecNO_DST)); // Invalid Delete operation (not found) - env(sponsor::set(sponsor, alice, tfDeleteObject), ter(tecNO_ENTRY)); + env(sponsor::set(sponsor, tfDeleteObject), + sponsor::sponseeAcc(alice), + ter(tecNO_ENTRY)); // DisallowIncomingSponsor: tested in other testcase // create sponsor to use above tests - env(sponsor::set(sponsor, alice, 0, 100, XRP(100)), ter(tesSUCCESS)); + env(sponsor::set(sponsor, 0, 100, XRP(100)), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); env.close(); } @@ -246,6 +260,49 @@ public: ter(tesSUCCESS)); } + void + testSimpleSponsorshipSet() + { + testcase("Simple SponsorshipSet"); + using namespace test::jtx; + Env env{*this, testable_amendments()}; + Account const alice("alice"); + Account const sponsor("sponsor"); + env.fund(XRP(10000), alice, sponsor); + env.close(); + + // + env(sponsor::set( + sponsor, + tfSponsorshipSetRequireSignForFee | + tfSponsorshipSetRequireSignForReserve, + 100, + XRP(100), + XRP(1)), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); + env.close(); + + // delete from sponsor + env(sponsor::del(sponsor), sponsor::sponseeAcc(alice), ter(tesSUCCESS)); + env.close(); + + env(sponsor::set( + sponsor, + tfSponsorshipSetRequireSignForFee | + tfSponsorshipSetRequireSignForReserve, + 100, + XRP(100), + XRP(1)), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); + env.close(); + + // delete from sponsee + env(sponsor::del(alice), sponsor::sponsorAcc(sponsor), ter(tesSUCCESS)); + env.close(); + } + void testTransferSponsor() { @@ -588,7 +645,8 @@ public: BEAST_EXPECT(env.balance(sponsor) == sponsorBalance); } - env(sponsor::set_fee(sponsor, alice, 0, XRP(100))); + env(sponsor::set_fee(sponsor, 0, XRP(100)), + sponsor::sponseeAcc(alice)); env.close(); { @@ -635,9 +693,10 @@ public: } // reset FeeAmount and MaxFee - env(sponsor::del(sponsor, alice)); + env(sponsor::del(sponsor), sponsor::sponseeAcc(alice)); env.close(); - env(sponsor::set_fee(sponsor, alice, 0, XRP(10), XRP(1))); + env(sponsor::set_fee(sponsor, 0, XRP(10), XRP(1)), + sponsor::sponseeAcc(alice)); env.close(); { @@ -695,7 +754,8 @@ public: // set flag env(sponsor::set_fee( - sponsor, alice, tfSponsorshipSetRequireSignForFee, XRP(10))); + sponsor, tfSponsorshipSetRequireSignForFee, XRP(10)), + sponsor::sponseeAcc(alice)); env.close(); env(pay(alice, bob, XRP(100)), @@ -706,7 +766,8 @@ public: // clear flag env(sponsor::set_fee( - sponsor, alice, tfSponsorshipClearRequireSignForFee, XRP(10))); + sponsor, tfSponsorshipClearRequireSignForFee, XRP(10)), + sponsor::sponseeAcc(alice)); env.close(); env(pay(alice, bob, XRP(100)), @@ -785,7 +846,8 @@ public: // set flag env(sponsor::set_reserve( - sponsor, alice, tfSponsorshipSetRequireSignForReserve, 10)); + sponsor, tfSponsorshipSetRequireSignForReserve, 10), + sponsor::sponseeAcc(alice)); env.close(); env(check::create(alice, bob, XRP(100)), @@ -796,7 +858,8 @@ public: // clear flag env(sponsor::set_reserve( - sponsor, alice, tfSponsorshipClearRequireSignForReserve, 1)); + sponsor, tfSponsorshipClearRequireSignForReserve, 1), + sponsor::sponseeAcc(alice)); env.close(); env(check::create(alice, bob, XRP(100)), @@ -2273,7 +2336,8 @@ public: env.close(); // Create sponsor should fail - env(sponsor::set(sponsor, alice, 0, 100, XRP(100)), + env(sponsor::set(sponsor, 0, 100, XRP(100)), + sponsor::sponseeAcc(alice), ter(tecNO_PERMISSION)); env.close(); @@ -2282,7 +2346,9 @@ public: env.close(); // Create sponsor - env(sponsor::set(sponsor, alice, 0, 100, XRP(100)), ter(tesSUCCESS)); + env(sponsor::set(sponsor, 0, 100, XRP(100)), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); env.close(); // set flag @@ -2290,11 +2356,15 @@ public: env.close(); // Update sponsor should success - env(sponsor::set(sponsor, alice, 0, 100, XRP(100)), ter(tesSUCCESS)); + env(sponsor::set(sponsor, 0, 100, XRP(100)), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); env.close(); - // Delete sponsor shoud success - env(sponsor::set(sponsor, alice, tfDeleteObject), ter(tesSUCCESS)); + // Delete sponsor should success + env(sponsor::set(sponsor, tfDeleteObject), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); env.close(); } void @@ -2313,7 +2383,8 @@ public: env.close(); // set sponsor - env(sponsor::set(sponsor, alice, 0, 100, XRP(100)), + env(sponsor::set(sponsor, 0, 100, XRP(100)), + sponsor::sponseeAcc(alice), ter(tesSUCCESS)); env.close(); @@ -2389,16 +2460,19 @@ public: env.close(); auto const testFeePermission = [&](TER result) { // FeeAmount - env(sponsor::set(alice, bob, 0, std::nullopt, XRP(100)), + env(sponsor::set(alice, 0, std::nullopt, XRP(100)), + sponsor::sponseeAcc(bob), delegate::as(carol), ter(result)); // MaxFee env(sponsor::set( - alice, bob, 0, std::nullopt, std::nullopt, XRP(100)), + alice, 0, std::nullopt, std::nullopt, XRP(100)), + sponsor::sponseeAcc(bob), delegate::as(carol), ter(result)); // SetRequireSignForFee flag - env(sponsor::set(alice, bob, tfSponsorshipSetRequireSignForFee), + env(sponsor::set(alice, tfSponsorshipSetRequireSignForFee), + sponsor::sponseeAcc(bob), delegate::as(carol), ter(result)); env.close(); @@ -2430,12 +2504,13 @@ public: auto const testReservePermission = [&](TER result) { // ReserveCount - env(sponsor::set(alice, bob, 0, 100), + env(sponsor::set(alice, 0, 100), + sponsor::sponseeAcc(bob), delegate::as(carol), ter(result)); // SetRequireSignForReserve flag - env(sponsor::set( - alice, bob, tfSponsorshipSetRequireSignForReserve), + env(sponsor::set(alice, tfSponsorshipSetRequireSignForReserve), + sponsor::sponseeAcc(bob), delegate::as(carol), ter(result)); env.close(); @@ -2492,6 +2567,8 @@ public: testMultiSigning(); // testInvalidSigninig(); // borh TxnSignature and Signers are present // -> error + testSimpleSponsorshipSet(); + testTransferSponsor(); testSponsorFee(); testSponsorAccount(); diff --git a/src/test/jtx/impl/sponsor.cpp b/src/test/jtx/impl/sponsor.cpp index 551a408ae1..befaaa337b 100644 --- a/src/test/jtx/impl/sponsor.cpp +++ b/src/test/jtx/impl/sponsor.cpp @@ -33,7 +33,6 @@ namespace sponsor { Json::Value set(jtx::Account const& account, - jtx::Account const& sponsee, uint32_t flags, std::optional reserveCount, std::optional feeAmount, @@ -42,7 +41,6 @@ set(jtx::Account const& account, Json::Value jv; jv[jss::TransactionType] = jss::SponsorshipSet; jv[jss::Account] = account.human(); - jv[sfSponsee.jsonName] = sponsee.human(); jv[sfFlags.jsonName] = flags; if (reserveCount) jv[sfReserveCount.jsonName] = *reserveCount; @@ -56,7 +54,6 @@ set(jtx::Account const& account, Json::Value set_fee( jtx::Account const& account, - jtx::Account const& sponsee, uint32_t flags, STAmount feeAmount, std::optional maxFee) @@ -64,7 +61,6 @@ set_fee( Json::Value jv; jv[jss::TransactionType] = jss::SponsorshipSet; jv[jss::Account] = account.human(); - jv[sfSponsee.jsonName] = sponsee.human(); jv[sfFlags.jsonName] = flags; jv[sfFeeAmount.jsonName] = feeAmount.getJson(JsonOptions::none); if (maxFee) @@ -73,28 +69,22 @@ set_fee( } Json::Value -set_reserve( - jtx::Account const& account, - jtx::Account const& sponsee, - uint32_t flags, - uint32_t reserveCount) +set_reserve(jtx::Account const& account, uint32_t flags, uint32_t reserveCount) { Json::Value jv; jv[jss::TransactionType] = jss::SponsorshipSet; jv[jss::Account] = account.human(); - jv[sfSponsee.jsonName] = sponsee.human(); jv[sfFlags.jsonName] = flags; jv[sfReserveCount.jsonName] = reserveCount; return jv; } Json::Value -del(jtx::Account const& account, jtx::Account const& sponsee) +del(jtx::Account const& account) { Json::Value jv; jv[jss::TransactionType] = jss::SponsorshipSet; jv[jss::Account] = account.human(); - jv[sfSponsee.jsonName] = sponsee.human(); jv[sfFlags.jsonName] = tfDeleteObject; return jv; } @@ -116,6 +106,12 @@ sponsorAcc::operator()(Env& env, JTx& jt) const jt.jv[sfSponsorAccount.jsonName] = sponsor_.human(); } +void +sponseeAcc::operator()(Env& env, JTx& jt) const +{ + jt.jv[sfSponsee.jsonName] = sponsee_.human(); +} + void as::operator()(Env& env, JTx& jt) const { diff --git a/src/test/jtx/sponsor.h b/src/test/jtx/sponsor.h index faab0bfb8c..db350207c8 100644 --- a/src/test/jtx/sponsor.h +++ b/src/test/jtx/sponsor.h @@ -31,7 +31,6 @@ namespace sponsor { Json::Value set(jtx::Account const& account, - jtx::Account const& sponsee, std::uint32_t flags, std::optional reserveCount = std::nullopt, std::optional feeAmount = std::nullopt, @@ -40,7 +39,6 @@ set(jtx::Account const& account, Json::Value set_fee( jtx::Account const& account, - jtx::Account const& sponsee, std::uint32_t flags, STAmount feeAmount, std::optional maxFee = std::nullopt); @@ -48,12 +46,11 @@ set_fee( Json::Value set_reserve( jtx::Account const& account, - jtx::Account const& sponsee, std::uint32_t flags, std::uint32_t reserveCount); Json::Value -del(jtx::Account const& account, jtx::Account const& sponsee); +del(jtx::Account const& account); Json::Value transfer( @@ -73,6 +70,21 @@ public: void operator()(jtx::Env&, jtx::JTx& jtx) const; }; + +struct sponseeAcc +{ +private: + jtx::Account sponsee_; + +public: + sponseeAcc(jtx::Account const& account) : sponsee_(account) + { + } + + void + operator()(jtx::Env&, jtx::JTx& jtx) const; +}; + struct as { private: diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index ceb091e72a..0dd346d4f7 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -987,12 +987,12 @@ public: { // Create a sponsorship env(sponsor::set( - alice, - gw, - tfSponsorshipSetRequireSignForFee, - 200, - XRP(100), - drops(10))); + alice, + tfSponsorshipSetRequireSignForFee, + 200, + XRP(100), + drops(10)), + sponsor::sponseeAcc(gw)); env.close(); // Find the sponsorship. diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index b27646dc2d..8e500cc865 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -876,7 +876,9 @@ class AccountTx_test : public beast::unit_test::suite checkTx(sponsor, jss::AccountSet); // set sponsor - env(sponsor::set(sponsor, alice, 0, 100, XRP(100)), ter(tesSUCCESS)); + env(sponsor::set(sponsor, 0, 100, XRP(100)), + sponsor::sponseeAcc(alice), + ter(tesSUCCESS)); env.close(); checkTx(alice, jss::SponsorshipSet); checkTx(sponsor, jss::SponsorshipSet); diff --git a/src/xrpld/app/tx/detail/SponsorshipSet.cpp b/src/xrpld/app/tx/detail/SponsorshipSet.cpp index 352d25cc2a..38af340930 100644 --- a/src/xrpld/app/tx/detail/SponsorshipSet.cpp +++ b/src/xrpld/app/tx/detail/SponsorshipSet.cpp @@ -36,7 +36,7 @@ SponsorshipSet::preflight(PreflightContext const& ctx) // check Flags { - if (ctx.tx.getFlags() & tfSponsorshipSetMask) + if (ctx.tx.isFlag(tfSponsorshipSetMask)) return temINVALID_FLAG; if (ctx.tx.isFlag(tfSponsorshipSetRequireSignForFee) && @@ -59,24 +59,22 @@ SponsorshipSet::preflight(PreflightContext const& ctx) } } - if (ctx.tx.isFieldPresent(sfSponsorAccount)) - { - // SponsorAccount is used when sponsee Deleting ltSponsorship - // Account => Sponsee of Sponsorshop - // SponsorAccount => Sponsor of Sponsorshop - // Sponsee => Sponsee of Sponsorshop - if (ctx.tx.getAccountID(sfAccount) == - ctx.tx.getAccountID(sfSponsorAccount) || - ctx.tx.getAccountID(sfSponsee) != - ctx.tx.getAccountID(sfSponsorAccount) || - !ctx.tx.isFlag(tfDeleteObject)) - return temMALFORMED; - } + if ((ctx.tx.isFieldPresent(sfSponsorAccount) && + ctx.tx.isFieldPresent(sfSponsee)) || + (!ctx.tx.isFieldPresent(sfSponsorAccount) && + !ctx.tx.isFieldPresent(sfSponsee))) + return temMALFORMED; + + // if (ctx.tx.isFieldPresent(sfSponsorAccount) && + // !ctx.tx.isFlag(tfDeleteObject)) + // return temMALFORMED; auto const sponsor = ctx.tx.isFieldPresent(sfSponsorAccount) ? ctx.tx.getAccountID(sfSponsorAccount) : ctx.tx.getAccountID(sfAccount); - auto const sponsee = ctx.tx.getAccountID(sfSponsee); + auto const sponsee = ctx.tx.isFieldPresent(sfSponsee) + ? ctx.tx.getAccountID(sfSponsee) + : ctx.tx.getAccountID(sfAccount); if (sponsee == sponsor) return temMALFORMED; @@ -119,6 +117,11 @@ SponsorshipSet::preflight(PreflightContext const& ctx) ctx.tx.isFieldPresent(sfMaxFee)) return temMALFORMED; } + else + { + if (!ctx.tx.isFieldPresent(sfSponsee)) + return temMALFORMED; + } return preflight2(ctx); } @@ -165,7 +168,12 @@ 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[sfSponsee]; + auto const sponsee = ctx.tx.isFieldPresent(sfSponsee) + ? ctx.tx.getAccountID(sfSponsee) + : ctx.tx.getAccountID(sfAccount); + + if (sponsee == sponsor) + return tecINTERNAL; // LCOV_EXCL_LINE // check Sponsee auto const sponseeSle = ctx.view.read(keylet::account(sponsee)); @@ -188,12 +196,17 @@ SponsorshipSet::preclaim(PreclaimContext const& ctx) TER SponsorshipSet::doApply() { - auto const sponseeAcc = ctx_.tx[sfSponsee]; + 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_; + if (sponseeAcc == sponsorAcc) + return tecINTERNAL; // LCOV_EXCL_LINE + auto const keylet = keylet::sponsor(sponsorAcc, sponseeAcc); auto const sponsorAccSle = ctx_.view().peek(keylet::account(sponsorAcc));