Co-authored-by: Akhil Kumar P <36399231+akhilkumarpilli@users.noreply.github.com> Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
parent
69878d8e6f
commit
1260f6703f
@ -23,7 +23,7 @@ require (
|
||||
cosmossdk.io/core v1.0.0 // main
|
||||
cosmossdk.io/errors v1.0.1
|
||||
cosmossdk.io/log v1.4.1
|
||||
cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e // main
|
||||
cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b // main
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e // main
|
||||
cosmossdk.io/store/v2 v2.0.0-20240731205446-aee9803a0af6 // main
|
||||
cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000
|
||||
@ -135,7 +135,7 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.20.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/common v0.57.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
|
||||
@ -24,8 +24,8 @@ cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE=
|
||||
cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k=
|
||||
cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA=
|
||||
cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e h1:5B5vereMsxfQsk8eXchBQPB1sc5POgYxZOBaUlST6WQ=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e/go.mod h1:rUve692/2QXV8ulpAG1mlytqiyW5nhZySY4ngmgJyQA=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b h1:FFixNVq2SbtRlYvr1fB/WikfYTRrA0o/35ImIhhZzrE=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b/go.mod h1:MgjYKtPEW4FPEYxh1h0idVBjgblFgdrAWkeqn7UOrVA=
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e h1:9eB2si1gT6c5ea8Jsh498Ei6E3Th1yMyuJgSLiT6D4Y=
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20=
|
||||
cosmossdk.io/store v1.0.0-rc.0.0.20240815194237-858ec2fcb897 h1:o024zaPHYtmUGL2BCX1ns9rfZmMc19U4hQ2CAPt2Xgg=
|
||||
@ -415,8 +415,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
|
||||
github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
|
||||
@ -11,7 +11,7 @@ require (
|
||||
cosmossdk.io/log v1.4.1
|
||||
cosmossdk.io/math v1.3.0
|
||||
cosmossdk.io/runtime/v2 v2.0.0-20240827121911-e98b8e96174f // main
|
||||
cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e // main
|
||||
cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b // main
|
||||
cosmossdk.io/server/v2/cometbft v0.0.0-00010101000000-000000000000
|
||||
cosmossdk.io/store/v2 v2.0.0-20240815194237-858ec2fcb897 // main
|
||||
cosmossdk.io/tools/confix v0.0.0-00010101000000-000000000000
|
||||
@ -185,7 +185,7 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.20.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/common v0.57.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
|
||||
@ -214,8 +214,8 @@ cosmossdk.io/runtime/v2 v2.0.0-20240827121911-e98b8e96174f h1:k/naA1PbdzhQ6EdiPh
|
||||
cosmossdk.io/runtime/v2 v2.0.0-20240827121911-e98b8e96174f/go.mod h1:SoCx1xyZn+tVPAtTAuLSEYjocVtZips+O2QLGBj99/c=
|
||||
cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA=
|
||||
cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e h1:5B5vereMsxfQsk8eXchBQPB1sc5POgYxZOBaUlST6WQ=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e/go.mod h1:rUve692/2QXV8ulpAG1mlytqiyW5nhZySY4ngmgJyQA=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b h1:FFixNVq2SbtRlYvr1fB/WikfYTRrA0o/35ImIhhZzrE=
|
||||
cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b/go.mod h1:MgjYKtPEW4FPEYxh1h0idVBjgblFgdrAWkeqn7UOrVA=
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e h1:9eB2si1gT6c5ea8Jsh498Ei6E3Th1yMyuJgSLiT6D4Y=
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20=
|
||||
cosmossdk.io/server/v2/stf v0.0.0-20240827095516-355f748add9e h1:A2JxCwJuoMRiBF8ZjpxRf+JO5cTSYw8Vc2iHImfHoKg=
|
||||
@ -764,8 +764,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
|
||||
github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
|
||||
@ -75,6 +75,7 @@ func initRootCmd[T transaction.Tx](
|
||||
rootCmd,
|
||||
newApp,
|
||||
logger,
|
||||
initServerConfig(),
|
||||
cometbft.New(&genericTxDecoder[T]{txConfig}, cometbft.DefaultServerOptions[T]()),
|
||||
grpc.New[T](),
|
||||
store.New[T](newApp),
|
||||
|
||||
@ -3,6 +3,8 @@ package cmd
|
||||
import (
|
||||
"strings"
|
||||
|
||||
serverv2 "cosmossdk.io/server/v2"
|
||||
|
||||
clientconfig "github.com/cosmos/cosmos-sdk/client/config"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
)
|
||||
@ -49,3 +51,20 @@ gas-adjustment = {{ .GasConfig.GasAdjustment }}
|
||||
|
||||
return customClientConfigTemplate, customClientConfig
|
||||
}
|
||||
|
||||
// Allow the chain developer to overwrite the server default app toml config.
|
||||
func initServerConfig() serverv2.ServerConfig {
|
||||
serverCfg := serverv2.DefaultServerConfig()
|
||||
// The server's default minimum gas price is set to "0stake" inside
|
||||
// app.toml. However, the chain developer can set a default app.toml value for their
|
||||
// validators here. Please update value based on chain denom.
|
||||
//
|
||||
// In summary:
|
||||
// - if you set serverCfg.MinGasPrices value, validators CAN tweak their
|
||||
// own app.toml to override, or use this default value.
|
||||
//
|
||||
// In simapp, we set the min gas prices to 0.
|
||||
serverCfg.MinGasPrices = "0stake"
|
||||
|
||||
return serverCfg
|
||||
}
|
||||
|
||||
@ -41,7 +41,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
flagMinGasPrices = "minimum-gas-prices"
|
||||
flagNodeDirPrefix = "node-dir-prefix"
|
||||
flagNumValidators = "validator-count"
|
||||
flagOutputDir = "output-dir"
|
||||
@ -72,7 +71,7 @@ func addTestnetFlagsToCmd(cmd *cobra.Command) {
|
||||
cmd.Flags().IntP(flagNumValidators, "n", 4, "Number of validators to initialize the testnet with")
|
||||
cmd.Flags().StringP(flagOutputDir, "o", "./.testnets", "Directory to store initialization data for the testnet")
|
||||
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(flagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
|
||||
cmd.Flags().String(serverv2.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
|
||||
cmd.Flags().String(flags.FlagKeyType, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for")
|
||||
|
||||
// support old flags name for backwards compatibility
|
||||
@ -129,7 +128,7 @@ Example:
|
||||
args.outputDir, _ = cmd.Flags().GetString(flagOutputDir)
|
||||
args.keyringBackend, _ = cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID)
|
||||
args.minGasPrices, _ = cmd.Flags().GetString(flagMinGasPrices)
|
||||
args.minGasPrices, _ = cmd.Flags().GetString(serverv2.FlagMinGasPrices)
|
||||
args.nodeDirPrefix, _ = cmd.Flags().GetString(flagNodeDirPrefix)
|
||||
args.nodeDaemonHome, _ = cmd.Flags().GetString(flagNodeDaemonHome)
|
||||
args.startingIPAddress, _ = cmd.Flags().GetString(flagStartingIPAddress)
|
||||
@ -337,6 +336,9 @@ func initTestnetFiles[T transaction.Tx](
|
||||
return err
|
||||
}
|
||||
|
||||
serverCfg := serverv2.DefaultServerConfig()
|
||||
serverCfg.MinGasPrices = args.minGasPrices
|
||||
|
||||
// Write server config
|
||||
cometServer := cometbft.New[T](
|
||||
&genericTxDecoder[T]{clientCtx.TxConfig},
|
||||
@ -345,7 +347,7 @@ func initTestnetFiles[T transaction.Tx](
|
||||
)
|
||||
storeServer := store.New[T](newApp)
|
||||
grpcServer := grpc.New[T](grpc.OverwriteDefaultConfig(grpcConfig))
|
||||
server := serverv2.NewServer(log.NewNopLogger(), cometServer, grpcServer, storeServer)
|
||||
server := serverv2.NewServer(log.NewNopLogger(), serverCfg, cometServer, grpcServer, storeServer)
|
||||
err = server.WriteConfig(filepath.Join(nodeDir, "config"))
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
)
|
||||
|
||||
func TestStakeUnstake(t *testing.T) {
|
||||
t.Skip("The fee deduction is not yet implemented in v2")
|
||||
// Scenario:
|
||||
// delegate tokens to validator
|
||||
// undelegate some tokens
|
||||
|
||||
@ -28,6 +28,10 @@ max-recv-msg-size = 10485760
|
||||
# The default value is math.MaxInt32.
|
||||
max-send-msg-size = 2147483647
|
||||
|
||||
[server]
|
||||
# minimum-gas-prices defines the price which a validator is willing to accept for processing a transaction. A transaction's fees must meet the minimum of any denomination specified in this config (e.g. 0.25token1;0.0001token2).
|
||||
minimum-gas-prices = '0stake'
|
||||
|
||||
[store]
|
||||
# The type of database for application and snapshots databases.
|
||||
app-db-backend = 'goleveldb'
|
||||
|
||||
@ -39,11 +39,12 @@ type v2KeyChangesMap map[string][]string
|
||||
|
||||
// list all the keys which are need to be modified in v2
|
||||
var v2KeyChanges = v2KeyChangesMap{
|
||||
"min-retain-blocks": []string{"comet.min-retain-blocks"},
|
||||
"index-events": []string{"comet.index-events"},
|
||||
"halt-height": []string{"comet.halt-height"},
|
||||
"halt-time": []string{"comet.halt-time"},
|
||||
"app-db-backend": []string{"store.app-db-backend"},
|
||||
"minimum-gas-prices": []string{"server.minimum-gas-prices"},
|
||||
"min-retain-blocks": []string{"comet.min-retain-blocks"},
|
||||
"index-events": []string{"comet.index-events"},
|
||||
"halt-height": []string{"comet.halt-height"},
|
||||
"halt-time": []string{"comet.halt-time"},
|
||||
"app-db-backend": []string{"store.app-db-backend"},
|
||||
"pruning-keep-recent": []string{
|
||||
"store.options.ss-pruning-option.keep-recent",
|
||||
"store.options.sc-pruning-option.keep-recent",
|
||||
|
||||
@ -2,8 +2,10 @@ package ante
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/core/event"
|
||||
"cosmossdk.io/core/transaction"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"cosmossdk.io/x/auth/types"
|
||||
@ -14,7 +16,7 @@ import (
|
||||
|
||||
// TxFeeChecker checks 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 the ABCI response.
|
||||
type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error)
|
||||
type TxFeeChecker func(ctx context.Context, tx transaction.Tx) (sdk.Coins, int64, error)
|
||||
|
||||
// DeductFeeDecorator deducts fees from the fee payer. The fee payer is the fee granter (if specified) or first signer of the tx.
|
||||
// If the fee payer does not have the funds to pay for the fees, return an InsufficientFunds error.
|
||||
@ -25,60 +27,78 @@ type DeductFeeDecorator struct {
|
||||
bankKeeper types.BankKeeper
|
||||
feegrantKeeper FeegrantKeeper
|
||||
txFeeChecker TxFeeChecker
|
||||
minGasPrices sdk.DecCoins
|
||||
}
|
||||
|
||||
func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) DeductFeeDecorator {
|
||||
if tfc == nil {
|
||||
tfc = checkTxFeeWithValidatorMinGasPrices
|
||||
}
|
||||
|
||||
return DeductFeeDecorator{
|
||||
func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) *DeductFeeDecorator {
|
||||
dfd := &DeductFeeDecorator{
|
||||
accountKeeper: ak,
|
||||
bankKeeper: bk,
|
||||
feegrantKeeper: fk,
|
||||
txFeeChecker: tfc,
|
||||
minGasPrices: sdk.NewDecCoins(),
|
||||
}
|
||||
|
||||
if tfc == nil {
|
||||
dfd.txFeeChecker = dfd.checkTxFeeWithValidatorMinGasPrices
|
||||
}
|
||||
|
||||
return dfd
|
||||
}
|
||||
|
||||
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// SetMinGasPrices sets the minimum-gas-prices value in the state of DeductFeeDecorator
|
||||
func (dfd *DeductFeeDecorator) SetMinGasPrices(minGasPrices sdk.DecCoins) {
|
||||
dfd.minGasPrices = minGasPrices
|
||||
}
|
||||
|
||||
// AnteHandle implements an AnteHandler decorator for the DeductFeeDecorator
|
||||
func (dfd *DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
dfd.minGasPrices = ctx.MinGasPrices()
|
||||
txPriority, err := dfd.innerValidateTx(ctx, tx)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
newCtx := ctx.WithPriority(txPriority)
|
||||
return next(newCtx, tx, false)
|
||||
}
|
||||
|
||||
func (dfd *DeductFeeDecorator) innerValidateTx(ctx context.Context, tx transaction.Tx) (priority int64, err error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the FeeTx interface")
|
||||
return 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the FeeTx interface")
|
||||
}
|
||||
|
||||
txService := dfd.accountKeeper.GetEnvironment().TransactionService
|
||||
execMode := txService.ExecMode(ctx)
|
||||
if execMode != transaction.ExecModeSimulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 {
|
||||
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas")
|
||||
}
|
||||
execMode := dfd.accountKeeper.GetEnvironment().TransactionService.ExecMode(ctx)
|
||||
headerInfo := dfd.accountKeeper.GetEnvironment().HeaderService.HeaderInfo(ctx)
|
||||
|
||||
var (
|
||||
priority int64
|
||||
err error
|
||||
)
|
||||
if execMode != transaction.ExecModeSimulate && headerInfo.Height > 0 && feeTx.GetGas() == 0 {
|
||||
return 0, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas")
|
||||
}
|
||||
|
||||
fee := feeTx.GetFee()
|
||||
if execMode != transaction.ExecModeSimulate {
|
||||
fee, priority, err = dfd.txFeeChecker(ctx, tx)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if err := dfd.checkDeductFee(ctx, tx, fee); err != nil {
|
||||
return ctx, err
|
||||
|
||||
if err := dfd.checkDeductFee(ctx, feeTx, fee); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
newCtx := ctx.WithPriority(priority)
|
||||
|
||||
return next(newCtx, tx, false)
|
||||
return priority, nil
|
||||
}
|
||||
|
||||
func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error {
|
||||
feeTx, ok := sdkTx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the FeeTx interface")
|
||||
}
|
||||
// ValidateTx implements an TxValidator for DeductFeeDecorator
|
||||
// Note: This method is applicable only for transactions that implement the sdk.FeeTx interface.
|
||||
func (dfd *DeductFeeDecorator) ValidateTx(ctx context.Context, tx transaction.Tx) error {
|
||||
_, err := dfd.innerValidateTx(ctx, tx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (dfd *DeductFeeDecorator) checkDeductFee(ctx context.Context, feeTx sdk.FeeTx, fee sdk.Coins) error {
|
||||
addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName)
|
||||
if len(addr) == 0 {
|
||||
return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName)
|
||||
@ -91,12 +111,10 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee
|
||||
// if feegranter set, deduct fee from feegranter account.
|
||||
// this works only when feegrant is enabled.
|
||||
if feeGranter != nil {
|
||||
feeGranterAddr := sdk.AccAddress(feeGranter)
|
||||
|
||||
if dfd.feegrantKeeper == nil {
|
||||
return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled")
|
||||
} else if !bytes.Equal(feeGranterAddr, feePayer) {
|
||||
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranterAddr, feePayer, fee, sdkTx.GetMsgs())
|
||||
} else if !bytes.Equal(feeGranter, feePayer) {
|
||||
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, feeTx.GetMsgs())
|
||||
if err != nil {
|
||||
granterAddr, acErr := dfd.accountKeeper.AddressCodec().BytesToString(feeGranter)
|
||||
if acErr != nil {
|
||||
@ -109,38 +127,34 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee
|
||||
return errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", granterAddr, payerAddr)
|
||||
}
|
||||
}
|
||||
|
||||
deductFeesFrom = feeGranterAddr
|
||||
deductFeesFrom = feeGranter
|
||||
}
|
||||
|
||||
// deduct the fees
|
||||
if !fee.IsZero() {
|
||||
err := DeductFees(dfd.bankKeeper, ctx, deductFeesFrom, fee)
|
||||
if err != nil {
|
||||
if err := DeductFees(dfd.bankKeeper, ctx, deductFeesFrom, fee); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
events := sdk.Events{
|
||||
sdk.NewEvent(
|
||||
sdk.EventTypeTx,
|
||||
sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()),
|
||||
sdk.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()),
|
||||
),
|
||||
if err := dfd.accountKeeper.GetEnvironment().EventService.EventManager(ctx).EmitKV(
|
||||
sdk.EventTypeTx,
|
||||
event.NewAttribute(sdk.AttributeKeyFee, fee.String()),
|
||||
event.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.EventManager().EmitEvents(events)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeductFees deducts fees from the given account.
|
||||
func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc []byte, fees sdk.Coins) error {
|
||||
func DeductFees(bankKeeper types.BankKeeper, ctx context.Context, acc []byte, fees sdk.Coins) error {
|
||||
if !fees.IsValid() {
|
||||
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees)
|
||||
}
|
||||
|
||||
err := bankKeeper.SendCoinsFromAccountToModule(ctx, sdk.AccAddress(acc), types.FeeCollectorName, fees)
|
||||
if err != nil {
|
||||
if err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.FeeCollectorName, fees); err != nil {
|
||||
return fmt.Errorf("failed to deduct fees: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +41,11 @@ func TestDeductFeeDecorator_ZeroGas(t *testing.T) {
|
||||
// Set IsCheckTx to true
|
||||
s.ctx = s.ctx.WithIsCheckTx(true)
|
||||
|
||||
// Set current block height in headerInfo
|
||||
headerInfo := s.ctx.HeaderInfo()
|
||||
headerInfo.Height = s.ctx.BlockHeight()
|
||||
s.ctx = s.ctx.WithHeaderInfo(headerInfo)
|
||||
|
||||
_, err = antehandler(s.ctx, tx, false)
|
||||
require.Error(t, err)
|
||||
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
|
||||
"cosmossdk.io/core/transaction"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
@ -12,7 +14,7 @@ import (
|
||||
|
||||
// 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) {
|
||||
func (dfd *DeductFeeDecorator) checkTxFeeWithValidatorMinGasPrices(ctx context.Context, tx transaction.Tx) (sdk.Coins, int64, error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
|
||||
@ -24,8 +26,8 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins,
|
||||
// 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.ExecMode() == sdk.ExecModeCheck { // NOTE: using environment here breaks the API of fee logic, an alternative must be found for server/v2. ref: https://github.com/cosmos/cosmos-sdk/issues/19640
|
||||
minGasPrices := ctx.MinGasPrices()
|
||||
if dfd.accountKeeper.GetEnvironment().TransactionService.ExecMode(ctx) == transaction.ExecModeCheck {
|
||||
minGasPrices := dfd.minGasPrices
|
||||
if !minGasPrices.IsZero() {
|
||||
requiredFees := make(sdk.Coins, len(minGasPrices))
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
gogoproto "github.com/cosmos/gogoproto/proto"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
grpcstatus "google.golang.org/grpc/status"
|
||||
@ -34,6 +35,9 @@ import (
|
||||
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
)
|
||||
|
||||
// flagMinGasPricesV2 is the flag name for the minimum gas prices in the main server v2 component.
|
||||
const flagMinGasPricesV2 = "server.minimum-gas-prices"
|
||||
|
||||
func init() {
|
||||
appconfig.RegisterModule(&txconfigv1.Config{},
|
||||
appconfig.Provide(ProvideModule),
|
||||
@ -50,7 +54,7 @@ type ModuleInputs struct {
|
||||
Codec codec.Codec
|
||||
ProtoFileResolver txsigning.ProtoFileResolver
|
||||
Environment appmodule.Environment
|
||||
// BankKeeper is the expected bank keeper to be passed to AnteHandlers
|
||||
// BankKeeper is the expected bank keeper to be passed to AnteHandlers / Tx Validators
|
||||
BankKeeper authtypes.BankKeeper `optional:"true"`
|
||||
MetadataBankKeeper BankKeeper `optional:"true"`
|
||||
AccountKeeper ante.AccountKeeper `optional:"true"`
|
||||
@ -58,8 +62,10 @@ type ModuleInputs struct {
|
||||
AccountAbstractionKeeper ante.AccountAbstractionKeeper `optional:"true"`
|
||||
CustomSignModeHandlers func() []txsigning.SignModeHandler `optional:"true"`
|
||||
CustomGetSigners []txsigning.CustomGetSigner `optional:"true"`
|
||||
UnorderedTxManager *unorderedtx.Manager `optional:"true"`
|
||||
ExtraTxValidators []appmodule.TxValidator[transaction.Tx] `optional:"true"`
|
||||
UnorderedTxManager *unorderedtx.Manager `optional:"true"`
|
||||
TxFeeChecker ante.TxFeeChecker `optional:"true"`
|
||||
Viper *viper.Viper `optional:"true"` // server v2
|
||||
}
|
||||
|
||||
type ModuleOutputs struct {
|
||||
@ -107,7 +113,40 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
baseAppOption := func(app *baseapp.BaseApp) {
|
||||
svd := ante.NewSigVerificationDecorator(
|
||||
in.AccountKeeper,
|
||||
txConfig.SignModeHandler(),
|
||||
ante.DefaultSigVerificationGasConsumer,
|
||||
in.AccountAbstractionKeeper,
|
||||
)
|
||||
|
||||
var (
|
||||
minGasPrices sdk.DecCoins
|
||||
feeTxValidator *ante.DeductFeeDecorator
|
||||
)
|
||||
if in.AccountKeeper != nil && in.BankKeeper != nil && in.Viper != nil {
|
||||
minGasPricesStr := in.Viper.GetString(flagMinGasPricesV2)
|
||||
minGasPrices, err = sdk.ParseDecCoins(minGasPricesStr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("invalid minimum gas prices: %v", err))
|
||||
}
|
||||
|
||||
feeTxValidator = ante.NewDeductFeeDecorator(in.AccountKeeper, in.BankKeeper, in.FeeGrantKeeper, in.TxFeeChecker)
|
||||
feeTxValidator.SetMinGasPrices(minGasPrices) // set min gas price in deduct fee decorator
|
||||
}
|
||||
|
||||
return ModuleOutputs{
|
||||
Module: NewAppModule(svd, feeTxValidator, in.ExtraTxValidators...),
|
||||
BaseAppOption: newBaseAppOption(txConfig, in),
|
||||
TxConfig: txConfig,
|
||||
TxConfigOptions: txConfigOptions,
|
||||
}
|
||||
}
|
||||
|
||||
// newBaseAppOption returns baseapp option that sets the ante handler and post handler
|
||||
// and set the tx encoder and decoder on baseapp.
|
||||
func newBaseAppOption(txConfig client.TxConfig, in ModuleInputs) func(app *baseapp.BaseApp) {
|
||||
return func(app *baseapp.BaseApp) {
|
||||
// AnteHandlers
|
||||
if !in.Config.SkipAnteHandler {
|
||||
anteHandler, err := newAnteHandler(txConfig, in)
|
||||
@ -145,20 +184,6 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
|
||||
app.SetTxDecoder(txConfig.TxDecoder())
|
||||
app.SetTxEncoder(txConfig.TxEncoder())
|
||||
}
|
||||
|
||||
svd := ante.NewSigVerificationDecorator(
|
||||
in.AccountKeeper,
|
||||
txConfig.SignModeHandler(),
|
||||
ante.DefaultSigVerificationGasConsumer,
|
||||
in.AccountAbstractionKeeper,
|
||||
)
|
||||
|
||||
return ModuleOutputs{
|
||||
Module: NewAppModule(svd, in.ExtraTxValidators...),
|
||||
TxConfig: txConfig,
|
||||
TxConfigOptions: txConfigOptions,
|
||||
BaseAppOption: baseAppOption,
|
||||
}
|
||||
}
|
||||
|
||||
func newAnteHandler(txConfig client.TxConfig, in ModuleInputs) (sdk.AnteHandler, error) {
|
||||
|
||||
@ -19,6 +19,7 @@ var (
|
||||
// This module is only useful for chains using server/v2. Ante/Post handlers are setup via baseapp options in depinject.
|
||||
type AppModule struct {
|
||||
sigVerification ante.SigVerificationDecorator
|
||||
feeTxValidator *ante.DeductFeeDecorator
|
||||
// txValidators contains tx validator that can be injected into the module via depinject.
|
||||
// tx validators should be module based, but it can happen that you do not want to create a new module
|
||||
// and simply depinject-it.
|
||||
@ -28,10 +29,12 @@ type AppModule struct {
|
||||
// NewAppModule creates a new AppModule object.
|
||||
func NewAppModule(
|
||||
sigVerification ante.SigVerificationDecorator,
|
||||
feeTxValidator *ante.DeductFeeDecorator,
|
||||
txValidators ...appmodulev2.TxValidator[transaction.Tx],
|
||||
) AppModule {
|
||||
return AppModule{
|
||||
sigVerification: sigVerification,
|
||||
feeTxValidator: feeTxValidator,
|
||||
txValidators: txValidators,
|
||||
}
|
||||
}
|
||||
@ -50,5 +53,9 @@ func (a AppModule) TxValidator(ctx context.Context, tx transaction.Tx) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := a.feeTxValidator.ValidateTx(ctx, tx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return a.sigVerification.ValidateTx(ctx, tx)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user