forked from ChihuahuaChain/chihuahua
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ante code to feeburn module + bump sdk 0.47.2
- Loading branch information
Showing
7 changed files
with
295 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package ante | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/x/auth/ante" | ||
) | ||
|
||
// HandlerOptions are the options required for constructing a default SDK AnteHandler. | ||
type HandlerOptions struct { | ||
ante.HandlerOptions | ||
} | ||
|
||
// NewAnteHandler returns an AnteHandler that checks and increments sequence | ||
// numbers, checks signatures & account numbers, and deducts fees from the first | ||
// signer. | ||
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { | ||
if options.AccountKeeper == nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder") | ||
} | ||
|
||
if options.BankKeeper == nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder") | ||
} | ||
|
||
if options.SignModeHandler == nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") | ||
} | ||
|
||
anteDecorators := []sdk.AnteDecorator{ | ||
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first | ||
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), | ||
ante.NewValidateBasicDecorator(), | ||
ante.NewTxTimeoutHeightDecorator(), | ||
ante.NewValidateMemoDecorator(options.AccountKeeper), | ||
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), | ||
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), | ||
ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators | ||
ante.NewValidateSigCountDecorator(options.AccountKeeper), | ||
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), | ||
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), | ||
ante.NewIncrementSequenceDecorator(options.AccountKeeper), | ||
} | ||
|
||
return sdk.ChainAnteDecorators(anteDecorators...), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package ante | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/x/auth/types" | ||
) | ||
|
||
// AccountKeeper defines the contract needed for AccountKeeper related APIs. | ||
// Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators. | ||
type AccountKeeper interface { | ||
GetParams(ctx sdk.Context) (params types.Params) | ||
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI | ||
SetAccount(ctx sdk.Context, acc types.AccountI) | ||
GetModuleAddress(moduleName string) sdk.AccAddress | ||
} | ||
|
||
// FeegrantKeeper defines the expected feegrant keeper. | ||
type FeegrantKeeper interface { | ||
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error | ||
} | ||
|
||
// BankKeeper defines the contract needed for supply related APIs (noalias) | ||
type BankKeeper interface { | ||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error | ||
BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package ante | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/x/auth/types" | ||
) | ||
|
||
// TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority, | ||
// the effective fee should be deducted later, and the priority should be returned in abci response. | ||
type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) | ||
|
||
// DeductFeeDecorator deducts fees from the first signer of the tx | ||
// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error | ||
// Call next AnteHandler if fees successfully deducted | ||
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator | ||
type DeductFeeDecorator struct { | ||
accountKeeper AccountKeeper | ||
bankKeeper BankKeeper | ||
feegrantKeeper FeegrantKeeper | ||
txFeeChecker TxFeeChecker | ||
} | ||
|
||
func NewDeductFeeDecorator(ak AccountKeeper, bk BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) DeductFeeDecorator { | ||
if tfc == nil { | ||
tfc = checkTxFeeWithValidatorMinGasPrices | ||
} | ||
|
||
return DeductFeeDecorator{ | ||
accountKeeper: ak, | ||
bankKeeper: bk, | ||
feegrantKeeper: fk, | ||
txFeeChecker: tfc, | ||
} | ||
} | ||
|
||
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { | ||
feeTx, ok := tx.(sdk.FeeTx) | ||
if !ok { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") | ||
} | ||
|
||
if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") | ||
} | ||
|
||
var ( | ||
priority int64 | ||
err error | ||
) | ||
|
||
fee := feeTx.GetFee() | ||
if !simulate { | ||
fee, priority, err = dfd.txFeeChecker(ctx, tx) | ||
if err != nil { | ||
return ctx, err | ||
} | ||
} | ||
if err := dfd.checkDeductFee(ctx, tx, fee); err != nil { | ||
return ctx, err | ||
} | ||
|
||
newCtx := ctx.WithPriority(priority) | ||
|
||
return next(newCtx, tx, simulate) | ||
} | ||
|
||
func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error { | ||
feeTx, ok := sdkTx.(sdk.FeeTx) | ||
if !ok { | ||
return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") | ||
} | ||
|
||
if addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil { | ||
return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) | ||
} | ||
|
||
feePayer := feeTx.FeePayer() | ||
feeGranter := feeTx.FeeGranter() | ||
deductFeesFrom := feePayer | ||
|
||
// if feegranter set deduct fee from feegranter account. | ||
// this works with only when feegrant enabled. | ||
if feeGranter != nil { | ||
if dfd.feegrantKeeper == nil { | ||
return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") | ||
} else if !feeGranter.Equals(feePayer) { | ||
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs()) | ||
if err != nil { | ||
return sdkerrors.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) | ||
} | ||
} | ||
|
||
deductFeesFrom = feeGranter | ||
} | ||
|
||
deductFeesFromAcc := dfd.accountKeeper.GetAccount(ctx, deductFeesFrom) | ||
if deductFeesFromAcc == nil { | ||
return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) | ||
} | ||
|
||
// deduct the fees | ||
if !fee.IsZero() { | ||
err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
events := sdk.Events{ | ||
sdk.NewEvent( | ||
sdk.EventTypeTx, | ||
sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), | ||
sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), | ||
), | ||
} | ||
ctx.EventManager().EmitEvents(events) | ||
|
||
return nil | ||
} | ||
|
||
// DeductFees deducts fees from the given account. | ||
func DeductFees(bankKeeper BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { | ||
if !fees.IsValid() { | ||
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) | ||
} | ||
|
||
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) | ||
if err != nil { | ||
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package ante | ||
|
||
import ( | ||
"math" | ||
|
||
sdkmath "cosmossdk.io/math" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per | ||
// unit of gas is fixed and set by each validator, can the tx priority is computed from the gas price. | ||
func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { | ||
feeTx, ok := tx.(sdk.FeeTx) | ||
if !ok { | ||
return nil, 0, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") | ||
} | ||
|
||
feeCoins := feeTx.GetFee() | ||
gas := feeTx.GetGas() | ||
|
||
// Ensure that the provided fees meet a minimum threshold for the validator, | ||
// if this is a CheckTx. This is only for local mempool purposes, and thus | ||
// is only ran on check tx. | ||
if ctx.IsCheckTx() { | ||
minGasPrices := ctx.MinGasPrices() | ||
if !minGasPrices.IsZero() { | ||
requiredFees := make(sdk.Coins, len(minGasPrices)) | ||
|
||
// Determine the required fees by multiplying each required minimum gas | ||
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit). | ||
glDec := sdkmath.LegacyNewDec(int64(gas)) | ||
for i, gp := range minGasPrices { | ||
fee := gp.Amount.Mul(glDec) | ||
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) | ||
} | ||
|
||
if !feeCoins.IsAnyGTE(requiredFees) { | ||
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees) | ||
} | ||
} | ||
} | ||
|
||
priority := getTxPriority(feeCoins, int64(gas)) | ||
return feeCoins, priority, nil | ||
} | ||
|
||
// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price | ||
// provided in a transaction. | ||
// NOTE: This implementation should be used with a great consideration as it opens potential attack vectors | ||
// where txs with multiple coins could not be prioritize as expected. | ||
func getTxPriority(fee sdk.Coins, gas int64) int64 { | ||
var priority int64 | ||
for _, c := range fee { | ||
p := int64(math.MaxInt64) | ||
gasPrice := c.Amount.QuoRaw(gas) | ||
if gasPrice.IsInt64() { | ||
p = gasPrice.Int64() | ||
} | ||
if priority == 0 || p < priority { | ||
priority = p | ||
} | ||
} | ||
|
||
return priority | ||
} |