mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 09:16:47 +00:00
MaxFee
This commit is contained in:
@@ -513,10 +513,11 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
LEDGER_ENTRY(ltSPONSORSHIP, 0x0085, Sponsorship, sponsorship, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfSponsee, soeREQUIRED},
|
||||
{sfFeeAmount, soeOPTIONAL},
|
||||
{sfMaxFee, soeOPTIONAL},
|
||||
{sfReserveCount, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfSponseeNode, soeREQUIRED},
|
||||
{sfFeeAmount, soeOPTIONAL},
|
||||
{sfReserveCount, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
#undef EXPAND
|
||||
|
||||
@@ -248,6 +248,7 @@ TYPED_SFIELD(sfSignatureReward, AMOUNT, 29)
|
||||
TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
|
||||
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
|
||||
TYPED_SFIELD(sfFeeAmount, AMOUNT, 32)
|
||||
TYPED_SFIELD(sfMaxFee, AMOUNT, 33)
|
||||
|
||||
// variable length (common)
|
||||
TYPED_SFIELD(sfPublicKey, VL, 1)
|
||||
|
||||
@@ -536,6 +536,7 @@ TRANSACTION(ttSPONSORSHIP_SET, 73, SponsorshipSet, Delegation::notDelegatable, (
|
||||
{sfSponsorAccount, soeOPTIONAL},
|
||||
{sfSponsee, soeREQUIRED},
|
||||
{sfFeeAmount, soeOPTIONAL},
|
||||
{sfMaxFee, soeOPTIONAL},
|
||||
{sfReserveCount, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
|
||||
@@ -137,6 +137,7 @@ public:
|
||||
env(sponsor::set(sponsor, alice, tfDeleteObject, 1), ter(temMALFORMED));
|
||||
env(sponsor::set(sponsor, alice, tfDeleteObject, std::nullopt, XRP(1)),
|
||||
ter(temMALFORMED));
|
||||
// TODO: test MaxFee with tfDeleteObject
|
||||
|
||||
//
|
||||
// preclaim
|
||||
@@ -492,6 +493,13 @@ public:
|
||||
env.fund(XRP(10000), alice, sponsor);
|
||||
env.close();
|
||||
|
||||
// not yet funded
|
||||
env(noop(alice),
|
||||
fee(drops(500)),
|
||||
sponsor::as(sponsor, tfSponsorFee),
|
||||
ter(tecNO_SPONSOR_PERMISSION));
|
||||
|
||||
// set sponsorship
|
||||
env(sponsor::set(sponsor, alice, 0, std::nullopt, XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
@@ -94,6 +94,18 @@ SponsorshipSet::preflight(PreflightContext const& ctx)
|
||||
return temBAD_AMOUNT;
|
||||
}
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfMaxFee))
|
||||
{
|
||||
auto const maxFee = ctx.tx.getFieldAmount(sfMaxFee);
|
||||
if (!isXRP(maxFee))
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (maxFee.xrp().drops() <= 0)
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
// TODO: check maxFee > basefee
|
||||
}
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfReserveCount))
|
||||
{
|
||||
if (ctx.tx.getFlags() & tfSponsorshipClearRequireSignForReserve)
|
||||
@@ -108,7 +120,8 @@ SponsorshipSet::preflight(PreflightContext const& ctx)
|
||||
if (ctx.tx.isFlag(tfDeleteObject))
|
||||
{
|
||||
if (ctx.tx.isFieldPresent(sfFeeAmount) ||
|
||||
ctx.tx.isFieldPresent(sfReserveCount))
|
||||
ctx.tx.isFieldPresent(sfReserveCount) ||
|
||||
ctx.tx.isFieldPresent(sfMaxFee))
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
@@ -188,6 +201,7 @@ SponsorshipSet::doApply()
|
||||
}
|
||||
|
||||
auto const feeAmount = ctx_.tx[~sfFeeAmount];
|
||||
auto const maxFee = ctx_.tx[~sfMaxFee];
|
||||
auto const reserveCount = ctx_.tx[~sfReserveCount];
|
||||
|
||||
auto reserveSponsorAccSle = getTxReserveSponsor(view(), ctx_.tx);
|
||||
@@ -214,6 +228,10 @@ SponsorshipSet::doApply()
|
||||
(*sponsorAccSle)[sfBalance] -= *feeAmount;
|
||||
(*newSle)[sfFeeAmount] = *feeAmount;
|
||||
}
|
||||
if (maxFee)
|
||||
{
|
||||
(*newSle)[sfMaxFee] = *maxFee;
|
||||
}
|
||||
if (reserveCount)
|
||||
{
|
||||
(*newSle)[sfReserveCount] = *reserveCount;
|
||||
@@ -244,11 +262,16 @@ SponsorshipSet::doApply()
|
||||
(*sponsorObjSle)[sfFeeAmount] += *feeAmount;
|
||||
}
|
||||
|
||||
if (maxFee)
|
||||
{
|
||||
(*sponsorObjSle)[sfMaxFee] = *maxFee;
|
||||
}
|
||||
|
||||
if (reserveCount)
|
||||
(*sponsorObjSle)[sfReserveCount] =
|
||||
(*sponsorObjSle)[sfReserveCount] + *reserveCount;
|
||||
|
||||
// TODO: update Flags?
|
||||
// update Flags
|
||||
auto flags = sponsorObjSle->getFieldU32(sfFlags);
|
||||
if (ctx_.tx.isFlag(tfSponsorshipSetRequireSignForFee))
|
||||
flags |= lsfSponsorshipRequireSignForFee;
|
||||
|
||||
@@ -259,25 +259,35 @@ Transactor::checkSponsor(ReadView const& view, STTx const& tx)
|
||||
auto const sponsorAcc = txSponsor.getAccountID(sfAccount);
|
||||
auto const sponseeAcc = tx.getAccountID(sfAccount);
|
||||
|
||||
auto const sponsorSle = view.read(keylet::sponsor(sponsorAcc, sponseeAcc));
|
||||
if (!sponsorSle)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const hasSignature = txSponsor.isFieldPresent(sfTxnSignature) ||
|
||||
!txSponsor.getFieldVL(sfSigningPubKey).empty() ||
|
||||
txSponsor.isFieldPresent(sfSigners);
|
||||
|
||||
if (txSponsor.isFlag(tfSponsorFee) &&
|
||||
sponsorSle->isFlag(lsfSponsorshipRequireSignForFee))
|
||||
auto const sponsorSle = view.read(keylet::sponsor(sponsorAcc, sponseeAcc));
|
||||
if (!hasSignature)
|
||||
{
|
||||
if (!hasSignature)
|
||||
// pre funded
|
||||
if (!sponsorSle)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
}
|
||||
if (txSponsor.isFlag(tfSponsorReserve) &&
|
||||
sponsorSle->isFlag(lsfSponsorshipRequireSignForReserve))
|
||||
else
|
||||
{
|
||||
if (!hasSignature)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
// co-signed
|
||||
if (!sponsorSle)
|
||||
return tesSUCCESS;
|
||||
|
||||
if (txSponsor.isFlag(tfSponsorFee) &&
|
||||
sponsorSle->isFlag(lsfSponsorshipRequireSignForFee))
|
||||
{
|
||||
if (!hasSignature)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
}
|
||||
if (txSponsor.isFlag(tfSponsorReserve) &&
|
||||
sponsorSle->isFlag(lsfSponsorshipRequireSignForReserve))
|
||||
{
|
||||
if (!hasSignature)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -359,21 +369,68 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
|
||||
if (feePaid == beast::zero)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const id = ctx.tx.getFeePayer();
|
||||
JLOG(ctx.j.trace()) << "Fee payer: " + to_string(id);
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
std::optional<XRPAmount> availableBalance;
|
||||
|
||||
auto const balance = (*sle)[sfBalance].xrp();
|
||||
if (ctx.tx.isFieldPresent(sfSponsor))
|
||||
{
|
||||
auto const txSponsor = ctx.tx.getFieldObject(sfSponsor);
|
||||
if (txSponsor.isFlag(tfSponsorFee) &&
|
||||
(!txSponsor.isFieldPresent(sfTxnSignature) &&
|
||||
!txSponsor.isFieldPresent(sfSigners)))
|
||||
{
|
||||
// use prefunded fee sponsor
|
||||
auto const keylet = keylet::sponsor(
|
||||
txSponsor.getAccountID(sfAccount), ctx.tx[sfAccount]);
|
||||
auto const sponsorSle = ctx.view.read(keylet);
|
||||
if (!sponsorSle)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
|
||||
if (balance < feePaid)
|
||||
XRPAmount const maxFee = sponsorSle->isFieldPresent(sfMaxFee)
|
||||
? sponsorSle->getFieldAmount(sfMaxFee).xrp()
|
||||
: INITIAL_XRP;
|
||||
|
||||
XRPAmount const feeAmount = sponsorSle->isFieldPresent(sfFeeAmount)
|
||||
? sponsorSle->getFieldAmount(sfFeeAmount).xrp()
|
||||
: XRPAmount(0);
|
||||
|
||||
// feePaid should <= maxFee
|
||||
if (feePaid > maxFee)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
|
||||
// feePaid should <= feeAmount
|
||||
if (feePaid > feeAmount)
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
|
||||
availableBalance = feeAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// proceed to use fee payer
|
||||
}
|
||||
}
|
||||
|
||||
if (!availableBalance)
|
||||
{
|
||||
auto const id = ctx.tx.getFeePayer();
|
||||
JLOG(ctx.j.trace()) << "Fee payer: " + to_string(id);
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
availableBalance = (*sle)[sfBalance].xrp();
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
availableBalance,
|
||||
"ripple::Transactor::checkFee : could not get balance for fee");
|
||||
|
||||
if (*availableBalance < feePaid)
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "Insufficient balance:" << " balance=" << to_string(balance)
|
||||
<< " paid=" << to_string(feePaid);
|
||||
<< "Insufficient balance:" << " balance="
|
||||
<< to_string(*availableBalance) << " paid=" << to_string(feePaid);
|
||||
|
||||
if ((balance > beast::zero) && !ctx.view.open())
|
||||
if ((*availableBalance > beast::zero) && !ctx.view.open())
|
||||
{
|
||||
// Closed ledger, non-zero balance, less than fee
|
||||
return tecINSUFF_FEE;
|
||||
|
||||
@@ -197,6 +197,11 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
|
||||
result = T::checkPriorTxAndLastLedger(ctx);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
return result;
|
||||
|
||||
result = T::checkSponsor(ctx.view, ctx.tx);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
return result;
|
||||
|
||||
@@ -207,11 +212,6 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
|
||||
result = T::checkPermission(ctx.view, ctx.tx);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
return result;
|
||||
|
||||
result = T::checkSponsor(ctx.view, ctx.tx);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
return result;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user