address SponsorAccount/Sponsee field changes

This commit is contained in:
tequ
2025-09-20 14:29:33 +09:00
parent f7e1d4bbb9
commit fed56b2eeb
7 changed files with 181 additions and 81 deletions

View File

@@ -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},

View File

@@ -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();

View File

@@ -33,7 +33,6 @@ namespace sponsor {
Json::Value
set(jtx::Account const& account,
jtx::Account const& sponsee,
uint32_t flags,
std::optional<uint32_t> reserveCount,
std::optional<STAmount> 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<STAmount> 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
{

View File

@@ -31,7 +31,6 @@ namespace sponsor {
Json::Value
set(jtx::Account const& account,
jtx::Account const& sponsee,
std::uint32_t flags,
std::optional<std::uint32_t> reserveCount = std::nullopt,
std::optional<STAmount> 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<STAmount> 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:

View File

@@ -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.

View File

@@ -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);

View File

@@ -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));