From aacb8e4a68ddccad008e9a64f267755a75a5a22a Mon Sep 17 00:00:00 2001 From: tequ Date: Mon, 23 Mar 2026 13:31:36 +0900 Subject: [PATCH] return tem error when SponsorReserve flag is set in Batch OuterTxn --- src/libxrpl/tx/transactors/system/Batch.cpp | 11 +++++++++ src/test/app/Sponsor_test.cpp | 25 +++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/libxrpl/tx/transactors/system/Batch.cpp b/src/libxrpl/tx/transactors/system/Batch.cpp index 80938f62ff..3423aaab48 100644 --- a/src/libxrpl/tx/transactors/system/Batch.cpp +++ b/src/libxrpl/tx/transactors/system/Batch.cpp @@ -194,6 +194,17 @@ Batch::preflight(PreflightContext const& ctx) return temINVALID_FLAG; } + if (ctx.tx.isFieldPresent(sfSponsorFlags)) + { + auto const sponsorFlags = ctx.tx.getFieldU32(sfSponsorFlags); + if (sponsorFlags & spfSponsorReserve) + { + JLOG(ctx.j.debug()) << "BatchTrace[" << parentBatchId << "]:" + << "spfSponsorReserve is not allowed on outer Batch."; + return temINVALID_FLAG; + } + } + auto const& rawTxns = ctx.tx.getFieldArray(sfRawTransactions); if (rawTxns.size() <= 1) { diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index b512ccda8f..de78cfc381 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -273,8 +273,7 @@ public: auto const vaultSle = env.le(keylet); BEAST_EXPECT(vaultSle); - Account const pseudoAcc( - "vault", vaultSle->getAccountID(sfAccount)); + Account const pseudoAcc("vault", vaultSle->getAccountID(sfAccount)); env.memoize(pseudoAcc); // Sponsee is a pseudo account -> tecNO_PERMISSION @@ -5288,7 +5287,7 @@ public: env(batch::outer(alice, seq, XRP(1), tfAllOrNothing), batch::inner(noop(alice), seq + 1), batch::inner(ticket::create(alice, 1), seq + 2), - sponsor::as(sponsor, spfSponsorReserve | spfSponsorFee), + sponsor::as(sponsor, spfSponsorFee), sig(sfSponsorSignature, sponsor), ter(tesSUCCESS)); env.close(); @@ -5302,6 +5301,24 @@ public: BEAST_EXPECT(env.balance(alice) == XRP(1000)); BEAST_EXPECT(env.balance(sponsor) == XRP(1000 - 1)); } + { + Env env{*this, testable_amendments()}; + env.fund(XRP(1000), alice, bob, sponsor); + env.close(); + + // spfSponsorReserve on outer Batch is rejected + for (auto const flags : {spfSponsorReserve | spfSponsorFee, spfSponsorReserve}) + { + auto const seq = env.seq(alice); + env(batch::outer(alice, seq, XRP(1), tfAllOrNothing), + batch::inner(noop(alice), seq + 1), + batch::inner(noop(alice), seq + 2), + sponsor::as(sponsor, flags), + sig(sfSponsorSignature, sponsor), + ter(temINVALID_FLAG)); + env.close(); + } + } { // test outer transaction with prefunded sponsor Env env{*this, testable_amendments()}; @@ -5319,7 +5336,7 @@ public: env(batch::outer(alice, seq, XRP(1), tfAllOrNothing), batch::inner(noop(alice), seq + 1), batch::inner(ticket::create(alice, 1), seq + 2), - sponsor::as(sponsor, spfSponsorReserve | spfSponsorFee), + sponsor::as(sponsor, spfSponsorFee), ter(tesSUCCESS)); env.close();