diff --git a/.changelog/unreleased/features/2629-add-query-local-min-gas-prices.md b/.changelog/unreleased/features/2629-add-query-local-min-gas-prices.md new file mode 100644 index 00000000000..2ad2b3700dc --- /dev/null +++ b/.changelog/unreleased/features/2629-add-query-local-min-gas-prices.md @@ -0,0 +1,3 @@ +- register NodeService to enable query /cosmos/base/node/v1beta1/config + gRPC query to disclose node operator's configured minimum-gas-price. + ([\#2629](https://github.com/cosmos/gaia/issues/2629)) \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e480bac1d31..93a43007170 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,8 +73,10 @@ jobs: **/**.go go.mod go.sum - - name: Build Docker Image + - name: Build Gaia Docker Image run: make docker-build-debug + - name: Build Hermes Docker Image + run: make docker-build-hermes - name: Test E2E run: make test-e2e diff --git a/Makefile b/Makefile index 45beabd3f94..ae9f3494443 100644 --- a/Makefile +++ b/Makefile @@ -234,7 +234,7 @@ docker-build-debug: # TODO: Push this to the Cosmos Dockerhub so we don't have to keep building it # in CI. docker-build-hermes: - @cd tests/e2e/docker; docker build -t cosmos/hermes-e2e:latest -f hermes.Dockerfile . + @cd tests/e2e/docker; docker build -t ghcr.io/cosmos/hermes-e2e:1.4.1 -f hermes.Dockerfile . docker-build-all: docker-build-debug docker-build-hermes diff --git a/ante/ante.go b/ante/ante.go index 5a53c94952d..be5ceb890cc 100644 --- a/ante/ante.go +++ b/ante/ante.go @@ -7,11 +7,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/ante" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" gaiaerrors "github.com/cosmos/gaia/v11/types/errors" - // gaiafeeante "github.com/cosmos/gaia/v11/x/globalfee/ante" + gaiafeeante "github.com/cosmos/gaia/v11/x/globalfee/ante" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC @@ -22,7 +23,8 @@ type HandlerOptions struct { GovKeeper *govkeeper.Keeper IBCkeeper *ibckeeper.Keeper GlobalFeeSubspace paramtypes.Subspace - StakingSubspace paramtypes.Subspace + StakingKeeper *stakingkeeper.Keeper + TxFeeChecker ante.TxFeeChecker } func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { @@ -39,10 +41,11 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { return nil, errorsmod.Wrap(gaiaerrors.ErrLogic, "IBC keeper is required for AnteHandler") } // TODO: Enable with Globalfee - // if opts.GlobalFeeSubspace.Name() == "" { - // return nil, errorsmod.Wrap(gaiaerrors.ErrNotFound, "globalfee param store is required for AnteHandler") - // } - if opts.StakingSubspace.Name() == "" { + if opts.GlobalFeeSubspace.Name() == "" { + return nil, errorsmod.Wrap(gaiaerrors.ErrNotFound, "globalfee param store is required for AnteHandler") + } + + if opts.StakingKeeper == nil { return nil, errorsmod.Wrap(gaiaerrors.ErrNotFound, "staking param store is required for AnteHandler") } if opts.GovKeeper == nil { @@ -62,8 +65,7 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { ante.NewValidateMemoDecorator(opts.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(opts.AccountKeeper), NewGovPreventSpamDecorator(opts.Codec, opts.GovKeeper), - // TODO: Enable with GlobalFee - // gaiafeeante.NewFeeDecorator(opts.GlobalFeeSubspace, opts.StakingSubspace), + gaiafeeante.NewFeeDecorator(opts.GlobalFeeSubspace, opts.StakingKeeper), ante.NewDeductFeeDecorator(opts.AccountKeeper, opts.BankKeeper, opts.FeegrantKeeper, opts.TxFeeChecker), ante.NewSetPubKeyDecorator(opts.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewValidateSigCountDecorator(opts.AccountKeeper), diff --git a/ante/gov_ante_test.go b/ante/gov_ante_test.go index fbfd86dccd3..9f3b0ceb9d1 100644 --- a/ante/gov_ante_test.go +++ b/ante/gov_ante_test.go @@ -12,18 +12,20 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/testutil/testdata" - // "github.com/cosmos/gaia/v11/ante" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + + "github.com/cosmos/gaia/v11/ante" gaiahelpers "github.com/cosmos/gaia/v11/app/helpers" gaiaapp "github.com/cosmos/gaia/v11/app" ) -// var ( -// insufficientCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 100)) -// minCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)) -// moreThanMinCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 2500000)) -// testAddr = sdk.AccAddress("test1") -// ) +var ( + insufficientCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 100)) + minCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)) + moreThanMinCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 2500000)) + testAddr = sdk.AccAddress("test1") +) type GovAnteHandlerTestSuite struct { suite.Suite @@ -53,41 +55,40 @@ func TestGovSpamPreventionSuite(t *testing.T) { suite.Run(t, new(GovAnteHandlerTestSuite)) } -// TODO: Enable with Global Fee -// func (s *GovAnteHandlerTestSuite) TestGlobalFeeMinimumGasFeeAnteHandler() { -// // setup test -// s.SetupTest() -// tests := []struct { -// title, description string -// proposalType string -// proposerAddr sdk.AccAddress -// initialDeposit sdk.Coins -// expectPass bool -// }{ -// {"Passing proposal 1", "the purpose of this proposal is to pass", govv1beta1.ProposalTypeText, testAddr, minCoins, true}, -// {"Passing proposal 2", "the purpose of this proposal is to pass with more coins than minimum", govv1beta1.ProposalTypeText, testAddr, moreThanMinCoins, true}, -// {"Failing proposal", "the purpose of this proposal is to fail", govv1beta1.ProposalTypeText, testAddr, insufficientCoins, false}, -// } -// -// decorator := ante.NewGovPreventSpamDecorator(s.app.AppCodec(), &s.app.GovKeeper) -// -// for _, tc := range tests { -// content, _ := govv1beta1.ContentFromProposalType(tc.title, tc.description, tc.proposalType) -// s.Require().NotNil(content) -// -// msg, err := govv1beta1.NewMsgSubmitProposal( -// content, -// tc.initialDeposit, -// tc.proposerAddr, -// ) -// -// s.Require().NoError(err) -// -// err = decorator.ValidateGovMsgs(s.ctx, []sdk.Msg{msg}) -// if tc.expectPass { -// s.Require().NoError(err, "expected %v to pass", tc.title) -// } else { -// s.Require().Error(err, "expected %v to fail", tc.title) -// } -// } -//} +func (s *GovAnteHandlerTestSuite) TestGlobalFeeMinimumGasFeeAnteHandler() { + // setup test + s.SetupTest() + tests := []struct { + title, description string + proposalType string + proposerAddr sdk.AccAddress + initialDeposit sdk.Coins + expectPass bool + }{ + {"Passing proposal 1", "the purpose of this proposal is to pass", govv1beta1.ProposalTypeText, testAddr, minCoins, true}, + {"Passing proposal 2", "the purpose of this proposal is to pass with more coins than minimum", govv1beta1.ProposalTypeText, testAddr, moreThanMinCoins, true}, + {"Failing proposal", "the purpose of this proposal is to fail", govv1beta1.ProposalTypeText, testAddr, insufficientCoins, false}, + } + + decorator := ante.NewGovPreventSpamDecorator(s.app.AppCodec(), &s.app.GovKeeper) + + for _, tc := range tests { + content, _ := govv1beta1.ContentFromProposalType(tc.title, tc.description, tc.proposalType) + s.Require().NotNil(content) + + msg, err := govv1beta1.NewMsgSubmitProposal( + content, + tc.initialDeposit, + tc.proposerAddr, + ) + + s.Require().NoError(err) + + err = decorator.ValidateGovMsgs(s.ctx, []sdk.Msg{msg}) + if tc.expectPass { + s.Require().NoError(err, "expected %v to pass", tc.title) + } else { + s.Require().Error(err, "expected %v to fail", tc.title) + } + } +} diff --git a/app/app.go b/app/app.go index 9534a22d12e..aaedd09e7c5 100644 --- a/app/app.go +++ b/app/app.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/testutil/testdata" + errorsmod "cosmossdk.io/errors" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" tmjson "github.com/cometbft/cometbft/libs/json" @@ -32,6 +33,7 @@ import ( "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -39,7 +41,6 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" @@ -52,7 +53,7 @@ import ( "github.com/cosmos/gaia/v11/app/upgrades" v11 "github.com/cosmos/gaia/v11/app/upgrades/v11" - // "github.com/cosmos/gaia/v11/x/globalfee" + "github.com/cosmos/gaia/v11/x/globalfee" // unnamed import of statik for swagger UI support _ "github.com/cosmos/cosmos-sdk/client/docs/statik" @@ -222,11 +223,14 @@ func NewGaiaApp( SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), SigGasConsumer: ante.DefaultSigVerificationGasConsumer, }, - Codec: appCodec, - IBCkeeper: app.IBCKeeper, - GovKeeper: &app.GovKeeper, - // GlobalFeeSubspace: app.GetSubspace(globalfee.ModuleName), - StakingSubspace: app.GetSubspace(stakingtypes.ModuleName), + Codec: appCodec, + IBCkeeper: app.IBCKeeper, + GovKeeper: &app.GovKeeper, + GlobalFeeSubspace: app.GetSubspace(globalfee.ModuleName), + StakingKeeper: app.StakingKeeper, + // If TxFeeChecker is nil the default ante TxFeeChecker is used + // so we use this no-op to keep the global fee module behaviour unchanged + TxFeeChecker: noOpTxFeeChecker, }, ) if err != nil { @@ -364,6 +368,7 @@ func (app *GaiaApp) RegisterTendermintService(clientCtx client.Context) { ) } +// RegisterTxService allows query minimum-gas-prices in app.toml func (app *GaiaApp) RegisterNodeService(clientCtx client.Context) { nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter()) } @@ -435,3 +440,14 @@ type EmptyAppOptions struct{} func (ao EmptyAppOptions) Get(_ string) interface{} { return nil } + +// noOpTxFeeChecker is an ante TxFeeChecker for the DeductFeeDecorator, see x/auth/ante/fee.go, +// it performs a no-op by not checking tx fees and always returns a zero tx priority +func noOpTxFeeChecker(_ sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + return feeTx.GetFee(), 0, nil +} diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index c558157537a..fa384395291 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -31,6 +31,8 @@ import ( govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/cosmos/gaia/v11/x/globalfee" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" @@ -435,7 +437,10 @@ func NewAppKeeper( // GetSubspace returns a param subspace for a given module name. func (appKeepers *AppKeepers) GetSubspace(moduleName string) paramstypes.Subspace { - subspace, _ := appKeepers.ParamsKeeper.GetSubspace(moduleName) + subspace, ok := appKeepers.ParamsKeeper.GetSubspace(moduleName) + if !ok { + panic("couldn't load subspace for module: " + moduleName) + } return subspace } @@ -457,8 +462,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(icahosttypes.SubModuleName) paramsKeeper.Subspace(pfmroutertypes.ModuleName).WithKeyTable(pfmroutertypes.ParamKeyTable()) - // TODO: Enable with Globalfee - // paramsKeeper.Subspace(globalfee.ModuleName) + paramsKeeper.Subspace(globalfee.ModuleName) paramsKeeper.Subspace(providertypes.ModuleName) return paramsKeeper diff --git a/app/modules.go b/app/modules.go index 43fc7944a87..c4ea6437ad0 100644 --- a/app/modules.go +++ b/app/modules.go @@ -56,7 +56,7 @@ import ( routertypes "github.com/strangelove-ventures/packet-forward-middleware/v7/router/types" gaiaparams "github.com/cosmos/gaia/v11/app/params" - // "github.com/cosmos/gaia/v11/x/globalfee" + "github.com/cosmos/gaia/v11/x/globalfee" ) var maccPerms = map[string][]string{ @@ -108,8 +108,7 @@ var ModuleBasics = module.NewBasicManager( vesting.AppModuleBasic{}, router.AppModuleBasic{}, ica.AppModuleBasic{}, - // TODO: Enable with Global Fee - // globalfee.AppModule{}, + globalfee.AppModule{}, ibcprovider.AppModuleBasic{}, consensus.AppModuleBasic{}, ) @@ -144,7 +143,7 @@ func appModules( authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ibc.NewAppModule(app.IBCKeeper), sdkparams.NewAppModule(app.ParamsKeeper), - // globalfee.NewAppModule(app.GetSubspace(globalfee.ModuleName)), + globalfee.NewAppModule(app.GetSubspace(globalfee.ModuleName)), app.TransferModule, app.ICAModule, app.PFMRouterModule, @@ -216,7 +215,7 @@ func orderBeginBlockers() []string { feegrant.ModuleName, paramstypes.ModuleName, vestingtypes.ModuleName, - // globalfee.ModuleName, + globalfee.ModuleName, providertypes.ModuleName, consensusparamtypes.ModuleName, } @@ -252,7 +251,7 @@ func orderEndBlockers() []string { paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, - // globalfee.ModuleName, + globalfee.ModuleName, providertypes.ModuleName, consensusparamtypes.ModuleName, } @@ -296,7 +295,7 @@ func orderInitBlockers() []string { // To resolve this issue, we should initialize the globalfee module after genutil, ensuring that the global // min fee is empty when gentx is called. // For more details, please refer to the following link: https://github.com/cosmos/gaia/issues/2489 - // globalfee.ModuleName, + globalfee.ModuleName, providertypes.ModuleName, consensusparamtypes.ModuleName, } diff --git a/go.mod b/go.mod index 15837fde7d5..2e25abfaaf3 100644 --- a/go.mod +++ b/go.mod @@ -35,11 +35,11 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v0.13.0 // indirect cloud.google.com/go/storage v1.29.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.3 // github.com/gravity-devs/liquidity v1.6.0 - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.55.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 + google.golang.org/grpc v1.55.0 ) require ( diff --git a/proto/gaia/globalfee/v1beta1/genesis.proto b/proto/gaia/globalfee/v1beta1/genesis.proto index 8368518261f..93f31965214 100644 --- a/proto/gaia/globalfee/v1beta1/genesis.proto +++ b/proto/gaia/globalfee/v1beta1/genesis.proto @@ -1,47 +1,43 @@ syntax = "proto3"; -// package gaia.globalfee.v1beta1; -// -// import "gogoproto/gogo.proto"; -// import "cosmos/base/v1beta1/coin.proto"; -// -// option go_package = "github.com/cosmos/gaia/x/globalfee/types"; -// -//// GenesisState - initial state of module -// message GenesisState { -// // Params of this module -// Params params = 1 [ -// (gogoproto.nullable) = false, -// (gogoproto.jsontag) = "params,omitempty" -// ]; -// } -// -//// Params defines the set of module parameters. -// message Params { -// // minimum_gas_prices stores the minimum gas price(s) for all TX on the -// chain. -// // When multiple coins are defined then they are accepted alternatively. -// // The list must be sorted by denoms asc. No duplicate denoms or zero -// amount -// // values allowed. For more information see -// // https://docs.cosmos.network/main/modules/auth#concepts -// repeated cosmos.base.v1beta1.DecCoin minimum_gas_prices = 1 [ -// (gogoproto.nullable) = false, -// (gogoproto.jsontag) = "minimum_gas_prices,omitempty", -// (gogoproto.moretags) = "yaml:\"minimum_gas_prices\"", -// (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" -// ]; -// -// // bypass_min_fee_msg_types defines a list of message type urls -// // that are free of fee charge. -// repeated string bypass_min_fee_msg_types = 2 [ -// (gogoproto.jsontag) = "bypass_min_fee_msg_types,omitempty", -// (gogoproto.moretags) = "yaml:\"bypass_min_fee_msg_types\"" -// ]; -// -// // max_total_bypass_min_fee_msg_gas_usage defines the total maximum gas -// usage -// // allowed for a transaction containing only messages of types in -// bypass_min_fee_msg_types -// // to bypass fee charge. -// uint64 max_total_bypass_min_fee_msg_gas_usage = 3; -// } +package gaia.globalfee.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/cosmos/gaia/x/globalfee/types"; + +// GenesisState - initial state of module +message GenesisState { + // Params of this module + Params params = 1 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "params,omitempty" + ]; +} + +// Params defines the set of module parameters. +message Params { + // minimum_gas_prices stores the minimum gas price(s) for all TX on the chain. + // When multiple coins are defined then they are accepted alternatively. + // The list must be sorted by denoms asc. No duplicate denoms or zero amount + // values allowed. For more information see + // https://docs.cosmos.network/main/modules/auth#concepts + repeated cosmos.base.v1beta1.DecCoin minimum_gas_prices = 1 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "minimum_gas_prices,omitempty", + (gogoproto.moretags) = "yaml:\"minimum_gas_prices\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" + ]; + + // bypass_min_fee_msg_types defines a list of message type urls + // that are free of fee charge. + repeated string bypass_min_fee_msg_types = 2 [ + (gogoproto.jsontag) = "bypass_min_fee_msg_types,omitempty", + (gogoproto.moretags) = "yaml:\"bypass_min_fee_msg_types\"" + ]; + + // max_total_bypass_min_fee_msg_gas_usage defines the total maximum gas usage + // allowed for a transaction containing only messages of types in bypass_min_fee_msg_types + // to bypass fee charge. + uint64 max_total_bypass_min_fee_msg_gas_usage = 3; +} diff --git a/proto/gaia/globalfee/v1beta1/query.proto b/proto/gaia/globalfee/v1beta1/query.proto index e6fb7f592c9..f797eb67f7b 100644 --- a/proto/gaia/globalfee/v1beta1/query.proto +++ b/proto/gaia/globalfee/v1beta1/query.proto @@ -1,27 +1,27 @@ syntax = "proto3"; -// package gaia.globalfee.v1beta1; -// -// import "gogoproto/gogo.proto"; -// import "google/api/annotations.proto"; -// import "gaia/globalfee/v1beta1/genesis.proto"; -// -// option go_package = "github.com/cosmos/gaia/x/globalfee/types"; -// -//// Query defines the gRPC querier service. -// service Query { -// rpc Params(QueryParamsRequest) -// returns (QueryParamsResponse) { -// option (google.api.http).get = -// "/gaia/globalfee/v1beta1/params"; -// } -// } -// -//// QueryMinimumGasPricesRequest is the request type for the -//// Query/MinimumGasPrices RPC method. -// message QueryParamsRequest {} -// -//// QueryMinimumGasPricesResponse is the response type for the -//// Query/MinimumGasPrices RPC method. -// message QueryParamsResponse { -// Params params = 1 [(gogoproto.nullable) = false]; -// } +package gaia.globalfee.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "gaia/globalfee/v1beta1/genesis.proto"; + +option go_package = "github.com/cosmos/gaia/x/globalfee/types"; + +// Query defines the gRPC querier service. +service Query { + rpc Params(QueryParamsRequest) + returns (QueryParamsResponse) { + option (google.api.http).get = + "/gaia/globalfee/v1beta1/params"; + } +} + +// QueryMinimumGasPricesRequest is the request type for the +// Query/MinimumGasPrices RPC method. +message QueryParamsRequest {} + +// QueryMinimumGasPricesResponse is the response type for the +// Query/MinimumGasPrices RPC method. +message QueryParamsResponse { + Params params = 1 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/tests/e2e/chain.go b/tests/e2e/chain.go index 81706d36a5c..c8a8eb43468 100644 --- a/tests/e2e/chain.go +++ b/tests/e2e/chain.go @@ -5,6 +5,7 @@ import ( "os" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" tmrand "github.com/cometbft/cometbft/libs/rand" "github.com/cosmos/cosmos-sdk/client" @@ -16,8 +17,8 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + paramsproptypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" gaiaparams "github.com/cosmos/gaia/v11/app/params" ) @@ -42,6 +43,8 @@ func init() { cryptocodec.RegisterInterfaces(encodingConfig.InterfaceRegistry) govv1types.RegisterInterfaces(encodingConfig.InterfaceRegistry) govv1beta1types.RegisterInterfaces(encodingConfig.InterfaceRegistry) + paramsproptypes.RegisterInterfaces(encodingConfig.InterfaceRegistry) + paramsproptypes.RegisterLegacyAminoCodec(encodingConfig.Amino) upgradetypes.RegisterInterfaces(encodingConfig.InterfaceRegistry) distribtypes.RegisterInterfaces(encodingConfig.InterfaceRegistry) diff --git a/tests/e2e/docker/hermes.Dockerfile b/tests/e2e/docker/hermes.Dockerfile index f6086acf861..8230f1f22ba 100644 --- a/tests/e2e/docker/hermes.Dockerfile +++ b/tests/e2e/docker/hermes.Dockerfile @@ -1,12 +1,9 @@ -FROM informalsystems/hermes:1.4.0 AS hermes-builder +FROM informalsystems/hermes:1.4.1 AS hermes-builder FROM debian:buster-slim USER root -COPY --chown=0:0 --from=hermes-builder /usr/lib/x86_64-linux-gnu/libssl.so.1.1 /usr/lib/x86_64-linux-gnu/libssl.so.1.1 -COPY --chown=0:0 --from=hermes-builder /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 COPY --from=hermes-builder /usr/bin/hermes /usr/local/bin/ RUN chmod +x /usr/local/bin/hermes -EXPOSE 3031 -# ENTRYPOINT ["hermes", "start"] +EXPOSE 3031 \ No newline at end of file diff --git a/tests/e2e/e2e_bypassminfee_test.go b/tests/e2e/e2e_bypassminfee_test.go index 6e27305c3b1..0913b1a8f08 100644 --- a/tests/e2e/e2e_bypassminfee_test.go +++ b/tests/e2e/e2e_bypassminfee_test.go @@ -1,184 +1,185 @@ package e2e -// import ( -// "time" - -// "cosmossdk.io/math" -// sdk "github.com/cosmos/cosmos-sdk/types" -// distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" -// ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" -// ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" -// ) - -// func (s *IntegrationTestSuite) testBypassMinFeeWithdrawReward(endpoint string) { -// // submit gov prop to change bypass-msg param to MsgWithdrawDelegatorReward -// submitterAddr := s.chainA.validators[0].keyInfo.GetAddress() -// submitter := submitterAddr.String() -// proposalCounter++ -// s.govProposeNewBypassMsgs([]string{sdk.MsgTypeURL(&distributiontypes.MsgWithdrawDelegatorReward{})}, proposalCounter, submitter, standardFees.String()) - -// paidFeeAmt := math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() -// payee := s.chainA.validators[0].keyInfo.GetAddress() - -// testCases := []struct { -// name string -// fee string -// changeMaxBypassGasUsage bool -// expErr bool -// }{ -// { -// "bypass-msg with fee in the denom of global fee, pass", -// paidFeeAmt + uatomDenom, -// false, -// false, -// }, -// { -// "bypass-msg with zero coin in the denom of global fee, pass", -// "0" + uatomDenom, -// false, -// false, -// }, -// { -// "bypass-msg with zero coin not in the denom of global fee, pass", -// "0" + photonDenom, -// false, -// false, -// }, -// { -// "bypass-msg with non-zero coin not in the denom of global fee, fail", -// paidFeeAmt + photonDenom, -// false, -// true, -// }, -// { -// "bypass-msg with zero coin in the denom of global fee and maxTotalBypassMinFeeMsgGasUsage set to 1, fail", -// "0" + uatomDenom, -// true, -// true, -// }, -// { -// "bypass-msg with non zero coin in the denom of global fee and maxTotalBypassMinFeeMsgGasUsage set to 1, pass", -// paidFeeAmt + uatomDenom, -// false, -// false, -// }, -// } - -// for _, tc := range testCases { - -// if tc.changeMaxBypassGasUsage { -// proposalCounter++ -// // change MaxTotalBypassMinFeeMsgGasUsage through governance proposal from 1_000_0000 to 1 -// s.govProposeNewMaxTotalBypassMinFeeMsgGasUsage(1, proposalCounter, submitter) -// } - -// // get delegator rewards -// rewards, err := queryDelegatorTotalRewards(endpoint, payee.String()) -// s.Require().NoError(err) - -// // get delegator stake balance -// oldBalance, err := getSpecificBalance(endpoint, payee.String(), stakeDenom) -// s.Require().NoError(err) - -// // withdraw rewards -// s.Run(tc.name, func() { -// s.execWithdrawAllRewards(s.chainA, 0, payee.String(), tc.fee, tc.expErr) -// }) - -// if !tc.expErr { -// // get updated balance -// incrBalance, err := getSpecificBalance(endpoint, payee.String(), stakeDenom) -// s.Require().NoError(err) - -// // compute sum of old balance and stake token rewards -// oldBalancePlusReward := rewards.GetTotal().Add(sdk.NewDecCoinFromCoin(oldBalance)) -// s.Require().Equal(oldBalancePlusReward[0].Denom, stakeDenom) - -// // check updated balance got increased by at least oldBalancePlusReward -// s.Require().True(sdk.NewDecCoinFromCoin(incrBalance).IsGTE(oldBalancePlusReward[0])) -// } -// } -// } - -// func (s *IntegrationTestSuite) testIBCBypassMsg() { -// // submit gov proposal to change bypass-msg param to -// // ["/ibc.core.channel.v1.MsgRecvPacket", -// // "/ibc.core.channel.v1.MsgAcknowledgement", -// // "/ibc.core.client.v1.MsgUpdateClient"] -// submitterAddr := s.chainA.validators[0].keyInfo.GetAddress() -// submitter := submitterAddr.String() -// proposalCounter++ -// s.govProposeNewBypassMsgs([]string{ -// sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), -// sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), -// }, proposalCounter, submitter, standardFees.String()) - -// // use hermes1 to test default ibc bypass-msg -// // -// // test 1: transaction only contains bypass-msgs, pass -// s.testTxContainsOnlyIBCBypassMsg() -// // test 2: test transactions contains both bypass and non-bypass msgs (sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}) -// s.testTxContainsMixBypassNonBypassMsg() -// // test 3: test bypass-msgs exceed the MaxBypassGasUsage -// s.testBypassMsgsExceedMaxBypassGasLimit() - -// // set the default bypass-msg back -// proposalCounter++ -// s.govProposeNewBypassMsgs([]string{ -// sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), -// sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeoutOnClose{}), -// }, proposalCounter, submitter, standardFees.String()) -// } - -// func (s *IntegrationTestSuite) testTxContainsOnlyIBCBypassMsg() { -// s.T().Logf("testing transaction contains only ibc bypass messages") -// ok := s.hermesTransfer(hermesConfigWithGasPrices, s.chainA.id, s.chainB.id, transferChannel, uatomDenom, 100, 1000, 1) -// s.Require().True(ok) - -// scrRelayerBalanceBefore, dstRelayerBalanceBefore := s.queryRelayerWalletsBalances() - -// pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel) -// s.Require().True(pass) -// pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel) -// s.Require().False(pendingPacketsExist) - -// // confirm relayer wallets do not pay fees -// scrRelayerBalanceAfter, dstRelayerBalanceAfter := s.queryRelayerWalletsBalances() -// s.Require().Equal(scrRelayerBalanceBefore.String(), scrRelayerBalanceAfter.String()) -// s.Require().Equal(dstRelayerBalanceBefore.String(), dstRelayerBalanceAfter.String()) -// } - -// func (s *IntegrationTestSuite) testTxContainsMixBypassNonBypassMsg() { -// s.T().Logf("testing transaction contains both bypass and non-bypass messages") -// // hermesTransfer with --timeout-height-offset=1 -// ok := s.hermesTransfer(hermesConfigWithGasPrices, s.chainA.id, s.chainB.id, transferChannel, uatomDenom, 100, 1, 1) -// s.Require().True(ok) -// // make sure that the transaction is timeout -// time.Sleep(3 * time.Second) -// pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel) -// s.Require().True(pendingPacketsExist) - -// pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel) -// s.Require().False(pass) -// // clear packets with paying fee, to not influence the next transaction -// pass = s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel) -// s.Require().True(pass) -// } - -// func (s *IntegrationTestSuite) testBypassMsgsExceedMaxBypassGasLimit() { -// s.T().Logf("testing bypass messages exceed MaxBypassGasUsage") -// ok := s.hermesTransfer(hermesConfigWithGasPrices, s.chainA.id, s.chainB.id, transferChannel, uatomDenom, 100, 1000, 12) -// s.Require().True(ok) -// pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel) -// s.Require().False(pass) - -// pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel) -// s.Require().True(pendingPacketsExist) - -// pass = s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel) -// s.Require().True(pass) -// } +import ( + "time" + + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +func (s *IntegrationTestSuite) testBypassMinFeeWithdrawReward(endpoint string) { + // submit gov prop to change bypass-msg param to MsgWithdrawDelegatorReward + submitterAddr, _ := s.chainA.validators[0].keyInfo.GetAddress() + submitter := submitterAddr.String() + proposalCounter++ + s.govProposeNewBypassMsgs([]string{sdk.MsgTypeURL(&distributiontypes.MsgWithdrawDelegatorReward{})}, proposalCounter, submitter, standardFees.String()) + + paidFeeAmt := math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() + payee, _ := s.chainA.validators[0].keyInfo.GetAddress() + + testCases := []struct { + name string + fee string + changeMaxBypassGasUsage bool + expErr bool + }{ + { + "bypass-msg with fee in the denom of global fee, pass", + paidFeeAmt + uatomDenom, + false, + false, + }, + { + "bypass-msg with zero coin in the denom of global fee, pass", + "0" + uatomDenom, + false, + false, + }, + { + "bypass-msg with zero coin not in the denom of global fee, pass", + "0" + photonDenom, + false, + false, + }, + { + "bypass-msg with non-zero coin not in the denom of global fee, fail", + paidFeeAmt + photonDenom, + false, + true, + }, + { + "bypass-msg with zero coin in the denom of global fee and maxTotalBypassMinFeeMsgGasUsage set to 1, fail", + "0" + uatomDenom, + true, + true, + }, + { + "bypass-msg with non zero coin in the denom of global fee and maxTotalBypassMinFeeMsgGasUsage set to 1, pass", + paidFeeAmt + uatomDenom, + false, + false, + }, + } + + for _, tc := range testCases { + + if tc.changeMaxBypassGasUsage { + proposalCounter++ + // change MaxTotalBypassMinFeeMsgGasUsage through governance proposal from 1_000_0000 to 1 + s.govProposeNewMaxTotalBypassMinFeeMsgGasUsage(1, proposalCounter, submitter) + } + + // get delegator rewards + rewards, err := queryDelegatorTotalRewards(endpoint, payee.String()) + s.Require().NoError(err) + + // get delegator stake balance + oldBalance, err := getSpecificBalance(endpoint, payee.String(), stakeDenom) + s.Require().NoError(err) + + // withdraw rewards + s.Run(tc.name, func() { + s.execWithdrawAllRewards(s.chainA, 0, payee.String(), tc.fee, tc.expErr) + }) + + if !tc.expErr { + // get updated balance + incrBalance, err := getSpecificBalance(endpoint, payee.String(), stakeDenom) + s.Require().NoError(err) + + // compute sum of old balance and stake token rewards + oldBalancePlusReward := rewards.GetTotal().Add(sdk.NewDecCoinFromCoin(oldBalance)) + s.Require().Equal(oldBalancePlusReward[0].Denom, stakeDenom) + + // check updated balance got increased by at least oldBalancePlusReward + s.Require().True(sdk.NewDecCoinFromCoin(incrBalance).IsGTE(oldBalancePlusReward[0])) + } + } +} + +func (s *IntegrationTestSuite) testIBCBypassMsg() { + // submit gov proposal to change bypass-msg param to + // ["/ibc.core.channel.v1.MsgRecvPacket", + // "/ibc.core.channel.v1.MsgAcknowledgement", + // "/ibc.core.client.v1.MsgUpdateClient"] + submitterAddr, _ := s.chainA.validators[0].keyInfo.GetAddress() + submitter := submitterAddr.String() + proposalCounter++ + s.govProposeNewBypassMsgs([]string{ + sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), + sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), + }, proposalCounter, submitter, standardFees.String()) + + // use hermes1 to test default ibc bypass-msg + // + // test 1: transaction only contains bypass-msgs, pass + s.testTxContainsOnlyIBCBypassMsg() + // test 2: test transactions contains both bypass and non-bypass msgs (sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}) + s.testTxContainsMixBypassNonBypassMsg() + // test 3: test bypass-msgs exceed the MaxBypassGasUsage + s.testBypassMsgsExceedMaxBypassGasLimit() + + // set the default bypass-msg back + proposalCounter++ + s.govProposeNewBypassMsgs([]string{ + sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), + sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeoutOnClose{}), + }, proposalCounter, submitter, standardFees.String()) +} + +func (s *IntegrationTestSuite) testTxContainsOnlyIBCBypassMsg() { + s.T().Logf("testing transaction contains only ibc bypass messages") + ok := s.hermesTransfer(hermesConfigWithGasPrices, s.chainA.id, s.chainB.id, transferChannel, uatomDenom, 100, 1000, 1) + s.Require().True(ok) + + scrRelayerBalanceBefore, dstRelayerBalanceBefore := s.queryRelayerWalletsBalances() + + pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel) + s.Require().True(pass) + pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel) + s.Require().False(pendingPacketsExist) + + // confirm relayer wallets do not pay fees + scrRelayerBalanceAfter, dstRelayerBalanceAfter := s.queryRelayerWalletsBalances() + s.Require().Equal(scrRelayerBalanceBefore.String(), scrRelayerBalanceAfter.String()) + s.Require().Equal(dstRelayerBalanceBefore.String(), dstRelayerBalanceAfter.String()) +} + +func (s *IntegrationTestSuite) testTxContainsMixBypassNonBypassMsg() { + s.T().Logf("testing transaction contains both bypass and non-bypass messages") + // hermesTransfer with --timeout-height-offset=1 + ok := s.hermesTransfer(hermesConfigWithGasPrices, s.chainA.id, s.chainB.id, transferChannel, uatomDenom, 100, 1, 1) + s.Require().True(ok) + // make sure that the transaction is timeout + time.Sleep(3 * time.Second) + pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel) + s.Require().True(pendingPacketsExist) + + pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel) + s.Require().False(pass) + // clear packets with paying fee, to not influence the next transaction + pass = s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel) + s.Require().True(pass) +} + +func (s *IntegrationTestSuite) testBypassMsgsExceedMaxBypassGasLimit() { + s.T().Logf("testing bypass messages exceed MaxBypassGasUsage") + ok := s.hermesTransfer(hermesConfigWithGasPrices, s.chainA.id, s.chainB.id, transferChannel, uatomDenom, 100, 1000, 12) + s.Require().True(ok) + pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel) + s.Require().False(pass) + + pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel) + s.Require().True(pendingPacketsExist) + + pass = s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel) + s.Require().True(pass) +} diff --git a/tests/e2e/e2e_exec_test.go b/tests/e2e/e2e_exec_test.go index da499a87023..7d6ecb8fc67 100644 --- a/tests/e2e/e2e_exec_test.go +++ b/tests/e2e/e2e_exec_test.go @@ -284,57 +284,56 @@ func (s *IntegrationTestSuite) execBankSend( s.executeGaiaTxCommand(ctx, c, gaiaCommand, valIdx, s.expectErrExecValidation(c, valIdx, expectErr)) } -// type txBankSend struct { -// from string -// to string -// amt string -// fees string -// log string -// expectErr bool -// } +type txBankSend struct { + from string + to string + amt string + fees string + log string + expectErr bool +} + +func (s *IntegrationTestSuite) execBankSendBatch( + c *chain, + valIdx int, //nolint:unparam + txs ...txBankSend, +) int { + sucessBankSendCount := 0 + + for i := range txs { + s.T().Logf(txs[i].log) + + s.execBankSend(c, valIdx, txs[i].from, txs[i].to, txs[i].amt, txs[i].fees, txs[i].expectErr) + if !txs[i].expectErr { + if !txs[i].expectErr { + sucessBankSendCount++ + } + } + } + + return sucessBankSendCount +} + +func (s *IntegrationTestSuite) execWithdrawAllRewards(c *chain, valIdx int, payee, fees string, expectErr bool) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + gaiaCommand := []string{ + gaiadBinary, + txCommand, + distributiontypes.ModuleName, + "withdraw-all-rewards", + fmt.Sprintf("--%s=%s", flags.FlagFrom, payee), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fees), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.executeGaiaTxCommand(ctx, c, gaiaCommand, valIdx, s.expectErrExecValidation(c, valIdx, expectErr)) +} -// func (s *IntegrationTestSuite) execBankSendBatch( -// -// c *chain, -// valIdx int, //nolint:unparam -// txs ...txBankSend, -// -// ) int { -// sucessBankSendCount := 0 -// -// for i := range txs { -// s.T().Logf(txs[i].log) -// -// s.execBankSend(c, valIdx, txs[i].from, txs[i].to, txs[i].amt, txs[i].fees, txs[i].expectErr) -// if !txs[i].expectErr { -// if !txs[i].expectErr { -// sucessBankSendCount++ -// } -// } -// } -// -// return sucessBankSendCount -// } -// -// func (s *IntegrationTestSuite) execWithdrawAllRewards(c *chain, valIdx int, payee, fees string, expectErr bool) { -// ctx, cancel := context.WithTimeout(context.Background(), time.Minute) -// defer cancel() -// -// gaiaCommand := []string{ -// gaiadBinary, -// txCommand, -// distributiontypes.ModuleName, -// "withdraw-all-rewards", -// fmt.Sprintf("--%s=%s", flags.FlagFrom, payee), -// fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fees), -// fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), -// "--keyring-backend=test", -// "--output=json", -// "-y", -// } -// -// s.executeGaiaTxCommand(ctx, c, gaiaCommand, valIdx, s.expectErrExecValidation(c, valIdx, expectErr)) -// } func (s *IntegrationTestSuite) execDistributionFundCommunityPool(c *chain, valIdx int, from, amt, fees string) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -624,6 +623,35 @@ func (s *IntegrationTestSuite) executeGaiaTxCommand(ctx context.Context, c *chai } } +func (s *IntegrationTestSuite) executeHermesCommand(ctx context.Context, hermesCmd []string) ([]byte, []byte) { + var ( + outBuf bytes.Buffer + errBuf bytes.Buffer + ) + exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{ + Context: ctx, + AttachStdout: true, + AttachStderr: true, + Container: s.hermesResource1.Container.ID, + User: "root", + Cmd: hermesCmd, + }) + s.Require().NoError(err) + + err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{ + Context: ctx, + Detach: false, + OutputStream: &outBuf, + ErrorStream: &errBuf, + }) + s.Require().NoError(err) + + stdOut := outBuf.Bytes() + stdErr := errBuf.Bytes() + + return stdOut, stdErr +} + func (s *IntegrationTestSuite) expectErrExecValidation(chain *chain, valIdx int, expectErr bool) func([]byte, []byte) bool { return func(stdOut []byte, stdErr []byte) bool { var txResp sdk.TxResponse diff --git a/tests/e2e/e2e_globalfee_proposal_test.go b/tests/e2e/e2e_globalfee_proposal_test.go index bb3e5fe5ad9..df26e7a376a 100644 --- a/tests/e2e/e2e_globalfee_proposal_test.go +++ b/tests/e2e/e2e_globalfee_proposal_test.go @@ -1,124 +1,123 @@ package e2e -// -// import ( -// "fmt" -// "strconv" -// "time" -// -// sdk "github.com/cosmos/cosmos-sdk/types" -// gov "github.com/cosmos/cosmos-sdk/x/gov/types" -// paramtypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" -//) -// -// func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { -// s.writeGovParamChangeProposalGlobalFees(s.chainA, newGlobalfee) -// chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) -// submitGovFlags := []string{"param-change", configFile(proposalGlobalFeeFilename)} -// depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} -// voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} -// -// // gov proposing new fees -// s.T().Logf("Proposal number: %d", proposalCounter) -// s.T().Logf("Submitting, deposit and vote legacy Gov Proposal: change global fee to %s", newGlobalfee.String()) -// s.runGovProcess(chainAAPIEndpoint, submitter, proposalCounter, paramtypes.ProposalTypeChange, submitGovFlags, depositGovFlags, voteGovFlags, "vote", false) -// -// // query the proposal status and new fee -// s.Require().Eventually( -// func() bool { -// proposal, err := queryGovProposal(chainAAPIEndpoint, proposalCounter) -// s.Require().NoError(err) -// return proposal.GetProposal().Status == gov.StatusPassed -// }, -// 15*time.Second, -// 5*time.Second, -// ) -// -// s.Require().Eventually( -// func() bool { -// globalFees, err := queryGlobalFees(chainAAPIEndpoint) -// s.T().Logf("After gov new global fee proposal: %s", globalFees.String()) -// s.Require().NoError(err) -// -// // attention: if global fee is empty, when query globalfee, it shows empty rather than default ante.DefaultZeroGlobalFee() = 0uatom. -// return globalFees.IsEqual(newGlobalfee) -// }, -// 15*time.Second, -// 5*time.Second, -// ) -//} -// -// func (s *IntegrationTestSuite) govProposeNewBypassMsgs(newBypassMsgs []string, proposalCounter int, submitter string, fees string) { //nolint:unparam -// s.writeGovParamChangeProposalBypassMsgs(s.chainA, newBypassMsgs) -// chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) -// submitGovFlags := []string{"param-change", configFile(proposalBypassMsgFilename)} -// depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} -// voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} -// -// // gov proposing new fees -// s.T().Logf("Proposal number: %d", proposalCounter) -// s.T().Logf("Submitting, deposit and vote legacy Gov Proposal: change bypass min fee msg types to %s", newBypassMsgs) -// s.runGovProcess(chainAAPIEndpoint, submitter, proposalCounter, paramtypes.ProposalTypeChange, submitGovFlags, depositGovFlags, voteGovFlags, "vote", false) -// -// // query the proposal status and new fee -// s.Require().Eventually( -// func() bool { -// proposal, err := queryGovProposal(chainAAPIEndpoint, proposalCounter) -// s.Require().NoError(err) -// return proposal.GetProposal().Status == gov.StatusPassed -// }, -// 15*time.Second, -// 5*time.Second, -// ) -// -// s.Require().Eventually( -// func() bool { -// bypassMsgs, err := queryBypassMsgs(chainAAPIEndpoint) -// s.T().Logf("After gov new global fee proposal: %s", newBypassMsgs) -// s.Require().NoError(err) -// -// // attention: if global fee is empty, when query globalfee, it shows empty rather than default ante.DefaultZeroGlobalFee() = 0uatom. -// s.Require().Equal(newBypassMsgs, bypassMsgs) -// return true -// }, -// 15*time.Second, -// 5*time.Second, -// ) -//} -// -// func (s *IntegrationTestSuite) govProposeNewMaxTotalBypassMinFeeMsgGasUsage(newGas uint64, proposalCounter int, submitter string) { -// s.writeGovParamChangeProposalMaxTotalBypass(s.chainA, newGas) -// chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) -// submitGovFlags := []string{"param-change", configFile(proposalMaxTotalBypassFilename)} -// depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} -// voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} -// -// // gov proposing new max gas usage for bypass msgs -// s.T().Logf("Proposal number: %d", proposalCounter) -// s.T().Logf("Submitting, deposit and vote legacy Gov Proposal: change maxTotalBypassMinFeeMsgGasUsage to %d", newGas) -// s.runGovProcess(chainAAPIEndpoint, submitter, proposalCounter, paramtypes.ProposalTypeChange, submitGovFlags, depositGovFlags, voteGovFlags, "vote", false) -// -// // query the proposal status and max gas usage for bypass msgs -// s.Require().Eventually( -// func() bool { -// proposal, err := queryGovProposal(chainAAPIEndpoint, proposalCounter) -// s.Require().NoError(err) -// return proposal.GetProposal().Status == gov.StatusPassed -// }, -// 15*time.Second, -// 5*time.Second, -// ) -// -// s.Require().Eventually( -// func() bool { -// gas, err := queryMaxTotalBypassMinFeeMsgGasUsage(chainAAPIEndpoint) -// s.T().Logf("After gov new global fee proposal: %d", gas) -// s.Require().NoError(err) -// -// s.Require().Equal(newGas, gas) -// return true -// }, -// 15*time.Second, -// 5*time.Second, -// ) -//} +import ( + "fmt" + "strconv" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" +) + +func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { + s.writeGovParamChangeProposalGlobalFees(s.chainA, newGlobalfee) + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + submitGovFlags := []string{"param-change", configFile(proposalGlobalFeeFilename)} + depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} + voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} + + // gov proposing new fees + s.T().Logf("Proposal number: %d", proposalCounter) + s.T().Logf("Submitting, deposit and vote legacy Gov Proposal: change global fee to %s", newGlobalfee.String()) + s.runGovProcess(chainAAPIEndpoint, submitter, proposalCounter, paramtypes.ProposalTypeChange, submitGovFlags, depositGovFlags, voteGovFlags, "vote", false) + + // query the proposal status and new fee + s.Require().Eventually( + func() bool { + proposal, err := queryGovProposal(chainAAPIEndpoint, proposalCounter) + s.Require().NoError(err) + return proposal.GetProposal().Status == govv1beta1.StatusPassed + }, + 15*time.Second, + 5*time.Second, + ) + + s.Require().Eventually( + func() bool { + globalFees, err := queryGlobalFees(chainAAPIEndpoint) + s.T().Logf("After gov new global fee proposal: %s", globalFees.String()) + s.Require().NoError(err) + + // attention: if global fee is empty, when query globalfee, it shows empty rather than default ante.DefaultZeroGlobalFee() = 0uatom. + return globalFees.IsEqual(newGlobalfee) + }, + 15*time.Second, + 5*time.Second, + ) +} + +func (s *IntegrationTestSuite) govProposeNewBypassMsgs(newBypassMsgs []string, proposalCounter int, submitter string, fees string) { //nolint:unparam + s.writeGovParamChangeProposalBypassMsgs(s.chainA, newBypassMsgs) + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + submitGovFlags := []string{"param-change", configFile(proposalBypassMsgFilename)} + depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} + voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} + + // gov proposing new fees + s.T().Logf("Proposal number: %d", proposalCounter) + s.T().Logf("Submitting, deposit and vote legacy Gov Proposal: change bypass min fee msg types to %s", newBypassMsgs) + s.runGovProcess(chainAAPIEndpoint, submitter, proposalCounter, paramtypes.ProposalTypeChange, submitGovFlags, depositGovFlags, voteGovFlags, "vote", false) + + // query the proposal status and new fee + s.Require().Eventually( + func() bool { + proposal, err := queryGovProposal(chainAAPIEndpoint, proposalCounter) + s.Require().NoError(err) + return proposal.GetProposal().Status == govv1beta1.StatusPassed + }, + 15*time.Second, + 5*time.Second, + ) + + s.Require().Eventually( + func() bool { + bypassMsgs, err := queryBypassMsgs(chainAAPIEndpoint) + s.T().Logf("After gov new global fee proposal: %s", newBypassMsgs) + s.Require().NoError(err) + + // attention: if global fee is empty, when query globalfee, it shows empty rather than default ante.DefaultZeroGlobalFee() = 0uatom. + s.Require().Equal(newBypassMsgs, bypassMsgs) + return true + }, + 15*time.Second, + 5*time.Second, + ) +} + +func (s *IntegrationTestSuite) govProposeNewMaxTotalBypassMinFeeMsgGasUsage(newGas uint64, proposalCounter int, submitter string) { + s.writeGovParamChangeProposalMaxTotalBypass(s.chainA, newGas) + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + submitGovFlags := []string{"param-change", configFile(proposalMaxTotalBypassFilename)} + depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} + voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} + + // gov proposing new max gas usage for bypass msgs + s.T().Logf("Proposal number: %d", proposalCounter) + s.T().Logf("Submitting, deposit and vote legacy Gov Proposal: change maxTotalBypassMinFeeMsgGasUsage to %d", newGas) + s.runGovProcess(chainAAPIEndpoint, submitter, proposalCounter, paramtypes.ProposalTypeChange, submitGovFlags, depositGovFlags, voteGovFlags, "vote", false) + + // query the proposal status and max gas usage for bypass msgs + s.Require().Eventually( + func() bool { + proposal, err := queryGovProposal(chainAAPIEndpoint, proposalCounter) + s.Require().NoError(err) + return proposal.GetProposal().Status == govv1beta1.StatusPassed + }, + 15*time.Second, + 5*time.Second, + ) + + s.Require().Eventually( + func() bool { + gas, err := queryMaxTotalBypassMinFeeMsgGasUsage(chainAAPIEndpoint) + s.T().Logf("After gov new global fee proposal: %d", gas) + s.Require().NoError(err) + + s.Require().Equal(newGas, gas) + return true + }, + 15*time.Second, + 5*time.Second, + ) +} diff --git a/tests/e2e/e2e_globalfee_test.go b/tests/e2e/e2e_globalfee_test.go index 27ab9f1e972..bcfffa5b4b0 100644 --- a/tests/e2e/e2e_globalfee_test.go +++ b/tests/e2e/e2e_globalfee_test.go @@ -1,335 +1,334 @@ package e2e -// -// import ( -// "fmt" -// "time" -// -// "cosmossdk.io/math" -// sdk "github.com/cosmos/cosmos-sdk/types" -//) -// -//// globalfee in genesis is set to be "0.00001uatom" -// func (s *IntegrationTestSuite) testQueryGlobalFeesInGenesis() { -// chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) -// feeInGenesis, err := sdk.ParseDecCoins(initialGlobalFeeAmt + uatomDenom) -// s.Require().NoError(err) -// s.Require().Eventually( -// func() bool { -// fees, err := queryGlobalFees(chainAAPIEndpoint) -// s.T().Logf("Global Fees in Genesis: %s", fees.String()) -// s.Require().NoError(err) -// -// return fees.IsEqual(feeInGenesis) -// }, -// 15*time.Second, -// 5*time.Second, -// ) -//} -// -///* -// global fee e2e tests: -// initial setup: initial globalfee = 0.00001uatom, min_gas_price = 0.00001uatom -// (This initial value setup is to pass other e2e tests) -// -//test1: gov proposal globalfee = [], min_gas_price=0.00001uatom, query globalfee still get empty -//- tx with fee denom photon, fail -//- tx with zero fee denom photon, fail -//- tx with fee denom uatom, pass -//- tx with fee empty, fail -// -//test2: gov propose globalfee = 0.000001uatom(lower than min_gas_price) -//- tx with fee higher than 0.000001uatom but lower than 0.00001uatom, fail -//- tx with fee higher than/equal to 0.00001uatom, pass -//- tx with fee photon fail -// -//test3: gov propose globalfee = 0.0001uatom (higher than min_gas_price) -//- tx with fee equal to 0.0001uatom, pass -//- tx with fee equal to 0.00001uatom, fail -// -//test4: gov propose globalfee = 0.000001uatom (lower than min_gas_price), 0photon -//- tx with fee 0.0000001photon, fail -//- tx with fee 0.000001photon, pass -//- tx with empty fee, pass -//- tx with fee photon pass -//- tx with fee 0photon, 0.000005uatom fail -//- tx with fee 0photon, 0.00001uatom pass -//test5: check balance correct: all the successful bank sent tokens are received -//test6: gov propose change back to initial globalfee = 0.00001photon, This is for not influence other e2e tests. -// */ -// func (s *IntegrationTestSuite) testGlobalFees() { -// chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) -// -// submitterAddr := s.chainA.validators[0].keyInfo.GetAddress() -// submitter := submitterAddr.String() -// recipientAddress := s.chainA.validators[1].keyInfo.GetAddress() -// recipient := recipientAddress.String() -// -// var beforeRecipientPhotonBalance sdk.Coin -// s.Require().Eventually( -// func() bool { -// var err error -// beforeRecipientPhotonBalance, err = getSpecificBalance(chainAAPIEndpoint, recipient, photonDenom) -// s.Require().NoError(err) -// -// return beforeRecipientPhotonBalance.IsValid() -// }, -// 10*time.Second, -// 5*time.Second, -// ) -// if beforeRecipientPhotonBalance.Equal(sdk.Coin{}) { -// beforeRecipientPhotonBalance = sdk.NewCoin(photonDenom, sdk.ZeroInt()) -// } -// -// sendAmt := int64(1000) -// token := sdk.NewInt64Coin(photonDenom, sendAmt) // send 1000photon each time -// sucessBankSendCount := 0 -// -// // ---------------------------- test1: globalfee empty -------------------------------------------- -// // prepare gov globalfee proposal -// emptyGlobalFee := sdk.DecCoins{} -// proposalCounter++ -// s.govProposeNewGlobalfee(emptyGlobalFee, proposalCounter, submitter, standardFees.String()) -// paidFeeAmt := math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() -// -// s.T().Logf("test case: empty global fee, globalfee=%s, min_gas_price=%s", emptyGlobalFee.String(), minGasPrice+uatomDenom) -// txBankSends := []txBankSend{ -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "0" + uatomDenom, -// log: "Tx fee is zero coin with correct denom: uatom, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "", -// log: "Tx fee is empty, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "4" + photonDenom, -// log: "Tx with wrong denom: photon, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "0" + photonDenom, -// log: "Tx fee is zero coins of wrong denom: photon, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmt + uatomDenom, -// log: "Tx fee is higher than min_gas_price, pass", -// expectErr: false, -// }, -// } -// sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) -// -// // ------------------ test2: globalfee lower than min_gas_price ----------------------------------- -// // prepare gov globalfee proposal -// lowGlobalFee := sdk.DecCoins{sdk.NewDecCoinFromDec(uatomDenom, sdk.MustNewDecFromStr(lowGlobalFeesAmt))} -// proposalCounter++ -// s.govProposeNewGlobalfee(lowGlobalFee, proposalCounter, submitter, standardFees.String()) -// -// paidFeeAmt = math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() -// paidFeeAmtLowMinGasHighGlobalFee := math.LegacyMustNewDecFromStr(lowGlobalFeesAmt). -// Mul(math.LegacyNewDec(2)). -// Mul(math.LegacyNewDec(gas)). -// String() -// paidFeeAmtLowGlobalFee := math.LegacyMustNewDecFromStr(lowGlobalFeesAmt).Quo(math.LegacyNewDec(2)).String() -// -// s.T().Logf("test case: global fee is lower than min_gas_price, globalfee=%s, min_gas_price=%s", lowGlobalFee.String(), minGasPrice+uatomDenom) -// txBankSends = []txBankSend{ -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmt + uatomDenom, -// log: "Tx fee higher than/equal to min_gas_price and global fee, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmtLowGlobalFee + uatomDenom, -// log: "Tx fee lower than/equal to min_gas_price and global fee, pass", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmtLowMinGasHighGlobalFee + uatomDenom, -// log: "Tx fee lower than/equal global fee and lower than min_gas_price, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmt + photonDenom, -// log: "Tx fee has wrong denom, fail", -// expectErr: true, -// }, -// } -// sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) -// -// // ------------------ test3: globalfee higher than min_gas_price ---------------------------------- -// // prepare gov globalfee proposal -// highGlobalFee := sdk.DecCoins{sdk.NewDecCoinFromDec(uatomDenom, sdk.MustNewDecFromStr(highGlobalFeeAmt))} -// proposalCounter++ -// s.govProposeNewGlobalfee(highGlobalFee, proposalCounter, submitter, paidFeeAmt+uatomDenom) -// -// paidFeeAmt = math.LegacyMustNewDecFromStr(highGlobalFeeAmt).Mul(math.LegacyNewDec(gas)).String() -// paidFeeAmtHigherMinGasLowerGalobalFee := math.LegacyMustNewDecFromStr(minGasPrice). -// Quo(math.LegacyNewDec(2)).String() -// -// s.T().Logf("test case: global fee is higher than min_gas_price, globalfee=%s, min_gas_price=%s", highGlobalFee.String(), minGasPrice+uatomDenom) -// txBankSends = []txBankSend{ -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmt + uatomDenom, -// log: "Tx fee is higher than/equal to global fee and min_gas_price, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmtHigherMinGasLowerGalobalFee + uatomDenom, -// log: "Tx fee is higher than/equal to min_gas_price but lower than global fee, fail", -// expectErr: true, -// }, -// } -// sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) -// -// // ---------------------------- test4: global fee with two denoms ----------------------------------- -// // prepare gov globalfee proposal -// mixGlobalFee := sdk.DecCoins{ -// sdk.NewDecCoinFromDec(photonDenom, sdk.NewDec(0)), -// sdk.NewDecCoinFromDec(uatomDenom, sdk.MustNewDecFromStr(lowGlobalFeesAmt)), -// }.Sort() -// proposalCounter++ -// s.govProposeNewGlobalfee(mixGlobalFee, proposalCounter, submitter, paidFeeAmt+uatomDenom) -// -// // equal to min_gas_price -// paidFeeAmt = math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() -// paidFeeAmtLow := math.LegacyMustNewDecFromStr(lowGlobalFeesAmt). -// Quo(math.LegacyNewDec(2)). -// Mul(math.LegacyNewDec(gas)). -// String() -// -// s.T().Logf("test case: global fees contain multiple denoms: one zero coin, one non-zero coin, globalfee=%s, min_gas_price=%s", mixGlobalFee.String(), minGasPrice+uatomDenom) -// txBankSends = []txBankSend{ -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmt + uatomDenom, -// log: "Tx with fee higher than/equal to one of denom's amount the global fee, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: paidFeeAmtLow + uatomDenom, -// log: "Tx with fee lower than one of denom's amount the global fee, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "", -// log: "Tx with fee empty fee, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "0" + photonDenom, -// log: "Tx with zero coin in the denom of zero coin of global fee, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "0" + photonDenom, -// log: "Tx with zero coin in the denom of zero coin of global fee, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "2" + photonDenom, -// log: "Tx with non-zero coin in the denom of zero coin of global fee, pass", -// expectErr: false, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "0" + photonDenom + "," + paidFeeAmtLow + uatomDenom, -// log: "Tx with multiple fee coins, zero coin and low fee, fail", -// expectErr: true, -// }, -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "0" + photonDenom + "," + paidFeeAmt + uatomDenom, -// log: "Tx with multiple fee coins, zero coin and high fee, pass", -// expectErr: false, -// }, -// -// { -// from: submitter, -// to: recipient, -// amt: token.String(), -// fees: "2" + photonDenom + "," + paidFeeAmt + uatomDenom, -// log: "Tx with multiple fee coins, all higher than global fee and min_gas_price", -// expectErr: false, -// }, -// } -// sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) -// -// // --------------------------------------------------------------------------- -// // check the balance is correct after previous txs -// s.Require().Eventually( -// func() bool { -// afterRecipientPhotonBalance, err := getSpecificBalance(chainAAPIEndpoint, recipient, photonDenom) -// s.Require().NoError(err) -// IncrementedPhoton := afterRecipientPhotonBalance.Sub(beforeRecipientPhotonBalance) -// photonSent := sdk.NewInt64Coin(photonDenom, sendAmt*int64(sucessBankSendCount)) -// return IncrementedPhoton.IsEqual(photonSent) -// }, -// time.Minute, -// 5*time.Second, -// ) -// -// // gov proposing to change back to original global fee -// s.T().Logf("Propose to change back to original global fees: %s", initialGlobalFeeAmt+uatomDenom) -// oldfees, err := sdk.ParseDecCoins(initialGlobalFeeAmt + uatomDenom) -// s.Require().NoError(err) -// proposalCounter++ -// s.govProposeNewGlobalfee(oldfees, proposalCounter, submitter, paidFeeAmt+photonDenom) -//} +import ( + "fmt" + "time" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// globalfee in genesis is set to be "0.00001uatom" +func (s *IntegrationTestSuite) testQueryGlobalFeesInGenesis() { + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + feeInGenesis, err := sdk.ParseDecCoins(initialGlobalFeeAmt + uatomDenom) + s.Require().NoError(err) + s.Require().Eventually( + func() bool { + fees, err := queryGlobalFees(chainAAPIEndpoint) + s.T().Logf("Global Fees in Genesis: %s", fees.String()) + s.Require().NoError(err) + + return fees.IsEqual(feeInGenesis) + }, + 15*time.Second, + 5*time.Second, + ) +} + +/* +global fee e2e tests: +initial setup: initial globalfee = 0.00001uatom, min_gas_price = 0.00001uatom +(This initial value setup is to pass other e2e tests) + +test1: gov proposal globalfee = [], min_gas_price=0.00001uatom, query globalfee still get empty +- tx with fee denom photon, fail +- tx with zero fee denom photon, fail +- tx with fee denom uatom, pass +- tx with fee empty, fail + +test2: gov propose globalfee = 0.000001uatom(lower than min_gas_price) +- tx with fee higher than 0.000001uatom but lower than 0.00001uatom, fail +- tx with fee higher than/equal to 0.00001uatom, pass +- tx with fee photon fail + +test3: gov propose globalfee = 0.0001uatom (higher than min_gas_price) +- tx with fee equal to 0.0001uatom, pass +- tx with fee equal to 0.00001uatom, fail + +test4: gov propose globalfee = 0.000001uatom (lower than min_gas_price), 0photon +- tx with fee 0.0000001photon, fail +- tx with fee 0.000001photon, pass +- tx with empty fee, pass +- tx with fee photon pass +- tx with fee 0photon, 0.000005uatom fail +- tx with fee 0photon, 0.00001uatom pass +test5: check balance correct: all the successful bank sent tokens are received +test6: gov propose change back to initial globalfee = 0.00001photon, This is for not influence other e2e tests. +*/ +func (s *IntegrationTestSuite) testGlobalFees() { + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + + submitterAddr, _ := s.chainA.validators[0].keyInfo.GetAddress() + submitter := submitterAddr.String() + recipientAddress, _ := s.chainA.validators[1].keyInfo.GetAddress() + recipient := recipientAddress.String() + + var beforeRecipientPhotonBalance sdk.Coin + s.Require().Eventually( + func() bool { + var err error + beforeRecipientPhotonBalance, err = getSpecificBalance(chainAAPIEndpoint, recipient, photonDenom) + s.Require().NoError(err) + + return beforeRecipientPhotonBalance.IsValid() + }, + 10*time.Second, + 5*time.Second, + ) + if beforeRecipientPhotonBalance.Equal(sdk.Coin{}) { + beforeRecipientPhotonBalance = sdk.NewCoin(photonDenom, sdk.ZeroInt()) + } + + sendAmt := int64(1000) + token := sdk.NewInt64Coin(photonDenom, sendAmt) // send 1000photon each time + sucessBankSendCount := 0 + + // ---------------------------- test1: globalfee empty -------------------------------------------- + // prepare gov globalfee proposal + emptyGlobalFee := sdk.DecCoins{} + proposalCounter++ + s.govProposeNewGlobalfee(emptyGlobalFee, proposalCounter, submitter, standardFees.String()) + paidFeeAmt := math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() + + s.T().Logf("test case: empty global fee, globalfee=%s, min_gas_price=%s", emptyGlobalFee.String(), minGasPrice+uatomDenom) + txBankSends := []txBankSend{ + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "0" + uatomDenom, + log: "Tx fee is zero coin with correct denom: uatom, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "", + log: "Tx fee is empty, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "4" + photonDenom, + log: "Tx with wrong denom: photon, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "0" + photonDenom, + log: "Tx fee is zero coins of wrong denom: photon, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmt + uatomDenom, + log: "Tx fee is higher than min_gas_price, pass", + expectErr: false, + }, + } + sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) + + // ------------------ test2: globalfee lower than min_gas_price ----------------------------------- + // prepare gov globalfee proposal + lowGlobalFee := sdk.DecCoins{sdk.NewDecCoinFromDec(uatomDenom, sdk.MustNewDecFromStr(lowGlobalFeesAmt))} + proposalCounter++ + s.govProposeNewGlobalfee(lowGlobalFee, proposalCounter, submitter, standardFees.String()) + + paidFeeAmt = math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() + paidFeeAmtLowMinGasHighGlobalFee := math.LegacyMustNewDecFromStr(lowGlobalFeesAmt). + Mul(math.LegacyNewDec(2)). + Mul(math.LegacyNewDec(gas)). + String() + paidFeeAmtLowGlobalFee := math.LegacyMustNewDecFromStr(lowGlobalFeesAmt).Quo(math.LegacyNewDec(2)).String() + + s.T().Logf("test case: global fee is lower than min_gas_price, globalfee=%s, min_gas_price=%s", lowGlobalFee.String(), minGasPrice+uatomDenom) + txBankSends = []txBankSend{ + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmt + uatomDenom, + log: "Tx fee higher than/equal to min_gas_price and global fee, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmtLowGlobalFee + uatomDenom, + log: "Tx fee lower than/equal to min_gas_price and global fee, pass", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmtLowMinGasHighGlobalFee + uatomDenom, + log: "Tx fee lower than/equal global fee and lower than min_gas_price, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmt + photonDenom, + log: "Tx fee has wrong denom, fail", + expectErr: true, + }, + } + sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) + + // ------------------ test3: globalfee higher than min_gas_price ---------------------------------- + // prepare gov globalfee proposal + highGlobalFee := sdk.DecCoins{sdk.NewDecCoinFromDec(uatomDenom, sdk.MustNewDecFromStr(highGlobalFeeAmt))} + proposalCounter++ + s.govProposeNewGlobalfee(highGlobalFee, proposalCounter, submitter, paidFeeAmt+uatomDenom) + + paidFeeAmt = math.LegacyMustNewDecFromStr(highGlobalFeeAmt).Mul(math.LegacyNewDec(gas)).String() + paidFeeAmtHigherMinGasLowerGalobalFee := math.LegacyMustNewDecFromStr(minGasPrice). + Quo(math.LegacyNewDec(2)).String() + + s.T().Logf("test case: global fee is higher than min_gas_price, globalfee=%s, min_gas_price=%s", highGlobalFee.String(), minGasPrice+uatomDenom) + txBankSends = []txBankSend{ + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmt + uatomDenom, + log: "Tx fee is higher than/equal to global fee and min_gas_price, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmtHigherMinGasLowerGalobalFee + uatomDenom, + log: "Tx fee is higher than/equal to min_gas_price but lower than global fee, fail", + expectErr: true, + }, + } + sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) + + // ---------------------------- test4: global fee with two denoms ----------------------------------- + // prepare gov globalfee proposal + mixGlobalFee := sdk.DecCoins{ + sdk.NewDecCoinFromDec(photonDenom, sdk.NewDec(0)), + sdk.NewDecCoinFromDec(uatomDenom, sdk.MustNewDecFromStr(lowGlobalFeesAmt)), + }.Sort() + proposalCounter++ + s.govProposeNewGlobalfee(mixGlobalFee, proposalCounter, submitter, paidFeeAmt+uatomDenom) + + // equal to min_gas_price + paidFeeAmt = math.LegacyMustNewDecFromStr(minGasPrice).Mul(math.LegacyNewDec(gas)).String() + paidFeeAmtLow := math.LegacyMustNewDecFromStr(lowGlobalFeesAmt). + Quo(math.LegacyNewDec(2)). + Mul(math.LegacyNewDec(gas)). + String() + + s.T().Logf("test case: global fees contain multiple denoms: one zero coin, one non-zero coin, globalfee=%s, min_gas_price=%s", mixGlobalFee.String(), minGasPrice+uatomDenom) + txBankSends = []txBankSend{ + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmt + uatomDenom, + log: "Tx with fee higher than/equal to one of denom's amount the global fee, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: paidFeeAmtLow + uatomDenom, + log: "Tx with fee lower than one of denom's amount the global fee, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "", + log: "Tx with fee empty fee, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "0" + photonDenom, + log: "Tx with zero coin in the denom of zero coin of global fee, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "0" + photonDenom, + log: "Tx with zero coin in the denom of zero coin of global fee, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "2" + photonDenom, + log: "Tx with non-zero coin in the denom of zero coin of global fee, pass", + expectErr: false, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "0" + photonDenom + "," + paidFeeAmtLow + uatomDenom, + log: "Tx with multiple fee coins, zero coin and low fee, fail", + expectErr: true, + }, + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "0" + photonDenom + "," + paidFeeAmt + uatomDenom, + log: "Tx with multiple fee coins, zero coin and high fee, pass", + expectErr: false, + }, + + { + from: submitter, + to: recipient, + amt: token.String(), + fees: "2" + photonDenom + "," + paidFeeAmt + uatomDenom, + log: "Tx with multiple fee coins, all higher than global fee and min_gas_price", + expectErr: false, + }, + } + sucessBankSendCount += s.execBankSendBatch(s.chainA, 0, txBankSends...) + + // --------------------------------------------------------------------------- + // check the balance is correct after previous txs + s.Require().Eventually( + func() bool { + afterRecipientPhotonBalance, err := getSpecificBalance(chainAAPIEndpoint, recipient, photonDenom) + s.Require().NoError(err) + IncrementedPhoton := afterRecipientPhotonBalance.Sub(beforeRecipientPhotonBalance) + photonSent := sdk.NewInt64Coin(photonDenom, sendAmt*int64(sucessBankSendCount)) + return IncrementedPhoton.IsEqual(photonSent) + }, + time.Minute, + 5*time.Second, + ) + + // gov proposing to change back to original global fee + s.T().Logf("Propose to change back to original global fees: %s", initialGlobalFeeAmt+uatomDenom) + oldfees, err := sdk.ParseDecCoins(initialGlobalFeeAmt + uatomDenom) + s.Require().NoError(err) + proposalCounter++ + s.govProposeNewGlobalfee(oldfees, proposalCounter, submitter, paidFeeAmt+photonDenom) +} diff --git a/tests/e2e/e2e_ibc_test.go b/tests/e2e/e2e_ibc_test.go index 2f2ce19ddb0..ea90f49ab62 100644 --- a/tests/e2e/e2e_ibc_test.go +++ b/tests/e2e/e2e_ibc_test.go @@ -1,20 +1,17 @@ package e2e import ( + "bufio" "bytes" "context" "encoding/json" "fmt" - "os" - "path" - "path/filepath" "strconv" "strings" "time" "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" ) @@ -32,104 +29,6 @@ type PacketMetadata struct { Forward *ForwardMetadata `json:"forward"` } -func (s *IntegrationTestSuite) runIBCRelayer() { - s.T().Log("starting Hermes relayer container...") - - tmpDir, err := os.MkdirTemp("", "gaia-e2e-testnet-hermes-") - s.Require().NoError(err) - s.tmpDirs = append(s.tmpDirs, tmpDir) - - gaiaAVal := s.chainA.validators[0] - gaiaBVal := s.chainB.validators[0] - - gaiaARly := s.chainA.genesisAccounts[relayerAccountIndex] - gaiaBRly := s.chainB.genesisAccounts[relayerAccountIndex] - - hermesCfgPath := path.Join(tmpDir, "hermes") - - s.Require().NoError(os.MkdirAll(hermesCfgPath, 0o755)) - _, err = copyFile( - filepath.Join("./scripts/", "hermes_bootstrap.sh"), - filepath.Join(hermesCfgPath, "hermes_bootstrap.sh"), - ) - s.Require().NoError(err) - - s.hermesResource, err = s.dkrPool.RunWithOptions( - &dockertest.RunOptions{ - Name: fmt.Sprintf("%s-%s-relayer", s.chainA.id, s.chainB.id), - Repository: "ghcr.io/informalsystems/hermes", - Tag: "1.4.1", - NetworkID: s.dkrNet.Network.ID, - Mounts: []string{ - fmt.Sprintf("%s/:/root/hermes", hermesCfgPath), - }, - PortBindings: map[docker.Port][]docker.PortBinding{ - "3031/tcp": {{HostIP: "", HostPort: "3031"}}, - }, - Env: []string{ - fmt.Sprintf("GAIA_A_E2E_CHAIN_ID=%s", s.chainA.id), - fmt.Sprintf("GAIA_B_E2E_CHAIN_ID=%s", s.chainB.id), - fmt.Sprintf("GAIA_A_E2E_VAL_MNEMONIC=%s", gaiaAVal.mnemonic), - fmt.Sprintf("GAIA_B_E2E_VAL_MNEMONIC=%s", gaiaBVal.mnemonic), - fmt.Sprintf("GAIA_A_E2E_RLY_MNEMONIC=%s", gaiaARly.mnemonic), - fmt.Sprintf("GAIA_B_E2E_RLY_MNEMONIC=%s", gaiaBRly.mnemonic), - fmt.Sprintf("GAIA_A_E2E_VAL_HOST=%s", s.valResources[s.chainA.id][0].Container.Name[1:]), - fmt.Sprintf("GAIA_B_E2E_VAL_HOST=%s", s.valResources[s.chainB.id][0].Container.Name[1:]), - }, - User: "root", - Entrypoint: []string{ - "sh", - "-c", - "chmod +x /root/hermes/hermes_bootstrap.sh && /root/hermes/hermes_bootstrap.sh", - }, - }, - noRestart, - ) - s.Require().NoError(err) - - // TODO: debug relayer REST endpoint - // endpoint := fmt.Sprintf("http://%s/state", s.hermesResource.GetHostPort("3031/tcp")) - // s.Require().Eventually( - // func() bool { - // resp, err := http.Get(endpoint) //nolint:gosec // this is a test - // if err != nil { - // return false - // } - - // defer resp.Body.Close() - - // bz, err := io.ReadAll(resp.Body) - // if err != nil { - // return false - // } - - // var respBody map[string]interface{} - // if err := json.Unmarshal(bz, &respBody); err != nil { - // return false - // } - - // status := respBody["status"].(string) - // result := respBody["result"].(map[string]interface{}) - - // return status == "success" && len(result["chains"].([]interface{})) == 2 - // }, - // 5*time.Minute, - // time.Second, - // "hermes relayer not healthy", - // ) - - s.T().Logf("started Hermes relayer container: %s", s.hermesResource.Container.ID) - - // XXX: Give time to both networks to start, otherwise we might see gRPC - // transport errors. - time.Sleep(10 * time.Second) - - // create the client, connection and channel between the two Gaia chains - s.createConnection() - time.Sleep(10 * time.Second) - s.createChannel() -} - func (s *IntegrationTestSuite) sendIBC(c *chain, valIdx int, sender, recipient, token, fees, note string) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -158,6 +57,120 @@ func (s *IntegrationTestSuite) sendIBC(c *chain, valIdx int, sender, recipient, s.T().Log("successfully sent IBC tokens") } +func (s *IntegrationTestSuite) hermesTransfer(configPath, srcChainID, dstChainID, srcChannelID, denom string, sendAmt, timeOutOffset, numMsg int) (success bool) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + hermesCmd := []string{ + hermesBinary, + fmt.Sprintf("--config=%s", configPath), + "tx", + "ft-transfer", + fmt.Sprintf("--dst-chain=%s", dstChainID), + fmt.Sprintf("--src-chain=%s", srcChainID), + fmt.Sprintf("--src-channel=%s", srcChannelID), + fmt.Sprintf("--src-port=%s", "transfer"), + fmt.Sprintf("--amount=%v", sendAmt), + fmt.Sprintf("--denom=%s", denom), + fmt.Sprintf("--timeout-height-offset=%v", timeOutOffset), + fmt.Sprintf("--number-msgs=%v", numMsg), + } + + stdout, stderr := s.executeHermesCommand(ctx, hermesCmd) + if strings.Contains(string(stdout), "ERROR") || strings.Contains(string(stderr), "ERROR") { + return false + } + + return true +} + +func (s *IntegrationTestSuite) hermesClearPacket(configPath, chainID, channelID string) (success bool) { //nolint:unparam + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + hermesCmd := []string{ + hermesBinary, + fmt.Sprintf("--config=%s", configPath), + "clear", + "packets", + fmt.Sprintf("--chain=%s", chainID), + fmt.Sprintf("--channel=%s", channelID), + fmt.Sprintf("--port=%s", "transfer"), + } + + stdout, stderr := s.executeHermesCommand(ctx, hermesCmd) + + if strings.Contains(string(stdout), "ERROR") || strings.Contains(string(stderr), "ERROR") { + return false + } + + return true +} + +type RelayerPacketsOutput struct { + Result struct { + Dst struct { + UnreceivedPackets []uint64 `json:"unreceived_packets"` + } `json:"dst"` + Src struct { + UnreceivedPackets []uint64 `json:"unreceived_packets"` + } `json:"src"` + } `json:"result"` + Status string `json:"status"` +} + +func (s *IntegrationTestSuite) hermesPendingPackets(configPath, chainID, channelID string) (pendingPackets bool) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + hermesCmd := []string{ + hermesBinary, + "--json", + fmt.Sprintf("--config=%s", configPath), + "query", + "packet", + "pending", + fmt.Sprintf("--chain=%s", chainID), + fmt.Sprintf("--channel=%s", channelID), + fmt.Sprintf("--port=%s", "transfer"), + } + + stdout, _ := s.executeHermesCommand(ctx, hermesCmd) + reader := bytes.NewReader(stdout) + sc := bufio.NewScanner(reader) + + var relayerPacketsOutput RelayerPacketsOutput + + // TODO: check why no error is never returned + // works atm because the last line of stdout is always the query output + for sc.Scan() { + sc.Bytes() + _ = json.Unmarshal(sc.Bytes(), &relayerPacketsOutput) + } + + // Check if "unreceived_packets" exists in "src" + return len(relayerPacketsOutput.Result.Src.UnreceivedPackets) != 0 +} + +func (s *IntegrationTestSuite) queryRelayerWalletsBalances() (sdk.Coin, sdk.Coin) { + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + acctAddrChainA, _ := s.chainA.genesisAccounts[relayerAccountIndexHermes1].keyInfo.GetAddress() + scrRelayerBalance, err := getSpecificBalance( + chainAAPIEndpoint, + acctAddrChainA.String(), + uatomDenom) + s.Require().NoError(err) + + chainBAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainB.id][0].GetHostPort("1317/tcp")) + acctAddrChainB, _ := s.chainB.genesisAccounts[relayerAccountIndexHermes1].keyInfo.GetAddress() + dstRelayerBalance, err := getSpecificBalance( + chainBAPIEndpoint, + acctAddrChainB.String(), + uatomDenom) + s.Require().NoError(err) + + return scrRelayerBalance, dstRelayerBalance +} + func (s *IntegrationTestSuite) createConnection() { s.T().Logf("connecting %s and %s chains via IBC", s.chainA.id, s.chainB.id) @@ -168,7 +181,7 @@ func (s *IntegrationTestSuite) createConnection() { Context: ctx, AttachStdout: true, AttachStderr: true, - Container: s.hermesResource.Container.ID, + Container: s.hermesResource0.Container.ID, User: "root", Cmd: []string{ "hermes", @@ -211,7 +224,7 @@ func (s *IntegrationTestSuite) createChannel() { Context: ctx, AttachStdout: true, AttachStderr: true, - Container: s.hermesResource.Container.ID, + Container: s.hermesResource0.Container.ID, User: "root", Cmd: []string{ "hermes", @@ -251,7 +264,6 @@ func (s *IntegrationTestSuite) createChannel() { } func (s *IntegrationTestSuite) testIBCTokenTransfer() { - time.Sleep(30 * time.Second) s.Run("send_uatom_to_chainB", func() { // require the recipient account receives the IBC tokens (IBC packets ACKd) var ( diff --git a/tests/e2e/e2e_rest_regression_test.go b/tests/e2e/e2e_rest_regression_test.go index 3ded9e09778..b5cfb97764c 100644 --- a/tests/e2e/e2e_rest_regression_test.go +++ b/tests/e2e/e2e_rest_regression_test.go @@ -42,6 +42,7 @@ const ( slashingParamsModuleQueryPath = "/cosmos/slashing/v1beta1/params" stakingParamsModuleQueryPath = "/cosmos/staking/v1beta1/params" missingPath = "/missing_endpoint" + localMinGasPriceQueryPath = "/cosmos/base/node/v1beta1/config" ) func (s *IntegrationTestSuite) testRestInterfaces() { @@ -72,6 +73,7 @@ func (s *IntegrationTestSuite) testRestInterfaces() { {slashingParamsModuleQueryPath, 200}, {stakingParamsModuleQueryPath, 200}, {missingPath, 501}, + {localMinGasPriceQueryPath, 200}, } ) diff --git a/tests/e2e/e2e_setup_test.go b/tests/e2e/e2e_setup_test.go index dac245a6ae6..84bdf6499e4 100644 --- a/tests/e2e/e2e_setup_test.go +++ b/tests/e2e/e2e_setup_test.go @@ -7,6 +7,7 @@ import ( "math/rand" "os" "os/exec" + "path" "path/filepath" "strconv" "strings" @@ -45,59 +46,69 @@ import ( ) const ( - gaiadBinary = "gaiad" - txCommand = "tx" - queryCommand = "query" - keysCommand = "keys" - gaiaHomePath = "/home/nonroot/.gaia" - // photonDenom = "photon" + gaiadBinary = "gaiad" + txCommand = "tx" + queryCommand = "query" + keysCommand = "keys" + gaiaHomePath = "/home/nonroot/.gaia" + photonDenom = "photon" uatomDenom = "uatom" stakeDenom = "stake" initBalanceStr = "110000000000stake,100000000000000000photon,100000000000000000uatom" minGasPrice = "0.00001" // // the test globalfee in genesis is the same as minGasPrice // // global fee lower/higher than min_gas_price - initialGlobalFeeAmt = "0.00001" - // lowGlobalFeesAmt = "0.000001" - // highGlobalFeeAmt = "0.0001" - // maxTotalBypassMinFeeMsgGasUsage = "1" - gas = 200000 - - govProposalBlockBuffer = 35 - relayerAccountIndex = 0 - numberOfEvidences = 10 - slashingShares int64 = 10000 - - // proposalGlobalFeeFilename = "proposal_globalfee.json" - // proposalBypassMsgFilename = "proposal_bypass_msg.json" - // proposalMaxTotalBypassFilename = "proposal_max_total_bypass.json" + initialGlobalFeeAmt = "0.00001" + lowGlobalFeesAmt = "0.000001" + highGlobalFeeAmt = "0.0001" + maxTotalBypassMinFeeMsgGasUsage = "1" + gas = 200000 + + govProposalBlockBuffer = 35 + relayerAccountIndexHermes0 = 0 + relayerAccountIndexHermes1 = 1 + numberOfEvidences = 10 + slashingShares int64 = 10000 + + proposalGlobalFeeFilename = "proposal_globalfee.json" + proposalBypassMsgFilename = "proposal_bypass_msg.json" + proposalMaxTotalBypassFilename = "proposal_max_total_bypass.json" proposalCommunitySpendFilename = "proposal_community_spend.json" -// proposalAddConsumerChainFilename = "proposal_add_consumer.json" -// proposalRemoveConsumerChainFilename = "proposal_remove_consumer.json" + // proposalAddConsumerChainFilename = "proposal_add_consumer.json" + // proposalRemoveConsumerChainFilename = "proposal_remove_consumer.json" + + hermesBinary = "hermes" + hermesConfigWithGasPrices = "/root/.hermes/config.toml" + hermesConfigNoGasPrices = "/root/.hermes/config-zero.toml" + transferChannel = "channel-0" ) var ( - gaiaConfigPath = filepath.Join(gaiaHomePath, "config") - stakingAmount = sdk.NewInt(100000000000) - stakingAmountCoin = sdk.NewCoin(uatomDenom, stakingAmount) - tokenAmount = sdk.NewCoin(uatomDenom, sdk.NewInt(3300000000)) // 3,300uatom - standardFees = sdk.NewCoin(uatomDenom, sdk.NewInt(330000)) // 0.33uatom - depositAmount = sdk.NewCoin(uatomDenom, sdk.NewInt(330000000)) // 3,300uatom - distModuleAddress = authtypes.NewModuleAddress(distrtypes.ModuleName).String() - govModuleAddress = authtypes.NewModuleAddress(govtypes.ModuleName).String() - proposalCounter = 0 + gaiaConfigPath = filepath.Join(gaiaHomePath, "config") + stakingAmount = sdk.NewInt(100000000000) + stakingAmountCoin = sdk.NewCoin(uatomDenom, stakingAmount) + tokenAmount = sdk.NewCoin(uatomDenom, sdk.NewInt(3300000000)) // 3,300uatom + standardFees = sdk.NewCoin(uatomDenom, sdk.NewInt(330000)) // 0.33uatom + depositAmount = sdk.NewCoin(uatomDenom, sdk.NewInt(330000000)) // 3,300uatom + distModuleAddress = authtypes.NewModuleAddress(distrtypes.ModuleName).String() + govModuleAddress = authtypes.NewModuleAddress(govtypes.ModuleName).String() + proposalCounter = 0 + HermesResource0Purged = false ) type IntegrationTestSuite struct { suite.Suite - tmpDirs []string - chainA *chain - chainB *chain - dkrPool *dockertest.Pool - dkrNet *dockertest.Network - hermesResource *dockertest.Resource - valResources map[string][]*dockertest.Resource + + tmpDirs []string + chainA *chain + chainB *chain + dkrPool *dockertest.Pool + dkrNet *dockertest.Network + hermesResource0 *dockertest.Resource + hermesResource1 *dockertest.Resource + + valResources map[string][]*dockertest.Resource } type AddressResponse struct { @@ -155,7 +166,8 @@ func (s *IntegrationTestSuite) SetupSuite() { s.runValidators(s.chainB, 10) time.Sleep(10 * time.Second) - s.runIBCRelayer() + s.runIBCRelayer0() + s.runIBCRelayer1() } func (s *IntegrationTestSuite) TearDownSuite() { @@ -170,8 +182,12 @@ func (s *IntegrationTestSuite) TearDownSuite() { s.T().Log("tearing down e2e integration test suite...") - if runIBCTest { - s.Require().NoError(s.dkrPool.Purge(s.hermesResource)) + s.Require().NoError(s.dkrPool.Purge(s.hermesResource1)) + // if runIBCTest, s.hermesResource0 already purged in TestIBC() + // in GovSoftwareUpgrade test, s.TearDownSuite() then s.SetupSuite() + // if IBCTest runs before GovSoftwareUpgrade, s.hermesResource0 is already purged. + if !HermesResource0Purged { + s.Require().NoError(s.dkrPool.Purge(s.hermesResource0)) } for _, vr := range s.valResources { @@ -193,12 +209,13 @@ func (s *IntegrationTestSuite) TearDownSuite() { func (s *IntegrationTestSuite) initNodes(c *chain) { s.Require().NoError(c.createAndInitValidators(2)) /* Adding 4 accounts to val0 local directory - c.genesisAccounts[0]: Relayer Wallet + c.genesisAccounts[0]: Relayer0 Wallet c.genesisAccounts[1]: ICA Owner c.genesisAccounts[2]: Test Account 1 c.genesisAccounts[3]: Test Account 2 + c.genesisAccounts[4]: Relayer1 Wallet */ - s.Require().NoError(c.addAccountFromMnemonic(4)) + s.Require().NoError(c.addAccountFromMnemonic(5)) // Initialize a genesis file for the first validator val0ConfigDir := c.validators[0].configDir() var addrAll []sdk.AccAddress @@ -599,99 +616,263 @@ func noRestart(config *docker.HostConfig) { } } -// func (s *IntegrationTestSuite) writeGovParamChangeProposalGlobalFees(c *chain, coins sdk.DecCoins) { -// type ParamInfo struct { -// Subspace string `json:"subspace"` -// Key string `json:"key"` -// Value sdk.DecCoins `json:"value"` -// } - -// type ParamChangeMessage struct { -// Title string `json:"title"` -// Description string `json:"description"` -// Changes []ParamInfo `json:"changes"` -// Deposit string `json:"deposit"` -// } - -// paramChangeProposalBody, err := json.MarshalIndent(ParamChangeMessage{ -// Title: "global fee test", -// Description: "global fee change", -// Changes: []ParamInfo{ -// { -// Subspace: "globalfee", -// Key: "MinimumGasPricesParam", -// Value: coins, -// }, -// }, -// Deposit: "1000uatom", -// }, "", " ") -// s.Require().NoError(err) - -// err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalGlobalFeeFilename), paramChangeProposalBody) -// s.Require().NoError(err) -// } - -// func (s *IntegrationTestSuite) writeGovParamChangeProposalBypassMsgs(c *chain, msgs []string) { -// type ParamInfo struct { -// Subspace string `json:"subspace"` -// Key string `json:"key"` -// Value []string `json:"value"` -// } - -// type ParamChangeMessage struct { -// Title string `json:"title"` -// Description string `json:"description"` -// Changes []ParamInfo `json:"changes"` -// Deposit string `json:"deposit"` -// } -// paramChangeProposalBody, err := json.MarshalIndent(ParamChangeMessage{ -// Title: "ChangeProposalBypassMsgs", -// Description: "global fee change", -// Changes: []ParamInfo{ -// { -// Subspace: "globalfee", -// Key: "BypassMinFeeMsgTypes", -// Value: msgs, -// }, -// }, -// Deposit: "1000uatom", -// }, "", " ") -// s.Require().NoError(err) - -// err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalBypassMsgFilename), paramChangeProposalBody) -// s.Require().NoError(err) -// } - -// func (s *IntegrationTestSuite) writeGovParamChangeProposalMaxTotalBypass(c *chain, gas uint64) { -// type ParamInfo struct { -// Subspace string `json:"subspace"` -// Key string `json:"key"` -// Value string `json:"value"` -// } - -// type ParamChangeMessage struct { -// Title string `json:"title"` -// Description string `json:"description"` -// Changes []ParamInfo `json:"changes"` -// Deposit string `json:"deposit"` -// } -// paramChangeProposalBody, err := json.MarshalIndent(ParamChangeMessage{ -// Title: "ChangeProposalMaxTotalBypass", -// Description: "global fee change", -// Changes: []ParamInfo{ -// { -// Subspace: "globalfee", -// Key: "MaxTotalBypassMinFeeMsgGasUsage", -// Value: strconv.FormatInt(int64(gas), 10), -// }, -// }, -// Deposit: "1000uatom", -// }, "", " ") -// s.Require().NoError(err) - -// err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalMaxTotalBypassFilename), paramChangeProposalBody) -// s.Require().NoError(err) -// } +// hermes0 is for ibc and packet-forward-middleware(PFM) test, hermes0 is keep running during the ibc and PFM test. +func (s *IntegrationTestSuite) runIBCRelayer0() { + s.T().Log("starting Hermes relayer container 0...") + + tmpDir, err := os.MkdirTemp("", "gaia-e2e-testnet-hermes-") + s.Require().NoError(err) + s.tmpDirs = append(s.tmpDirs, tmpDir) + + gaiaAVal := s.chainA.validators[0] + gaiaBVal := s.chainB.validators[0] + + gaiaARly := s.chainA.genesisAccounts[relayerAccountIndexHermes0] + gaiaBRly := s.chainB.genesisAccounts[relayerAccountIndexHermes0] + + hermesCfgPath := path.Join(tmpDir, "hermes") + + s.Require().NoError(os.MkdirAll(hermesCfgPath, 0o755)) + _, err = copyFile( + filepath.Join("./scripts/", "hermes_bootstrap.sh"), + filepath.Join(hermesCfgPath, "hermes_bootstrap.sh"), + ) + s.Require().NoError(err) + + s.hermesResource0, err = s.dkrPool.RunWithOptions( + &dockertest.RunOptions{ + Name: fmt.Sprintf("%s-%s-relayer-0", s.chainA.id, s.chainB.id), + Repository: "ghcr.io/cosmos/hermes-e2e", + Tag: "1.4.1", + NetworkID: s.dkrNet.Network.ID, + Mounts: []string{ + fmt.Sprintf("%s/:/root/hermes", hermesCfgPath), + }, + PortBindings: map[docker.Port][]docker.PortBinding{ + "3031/tcp": {{HostIP: "", HostPort: "3031"}}, + }, + Env: []string{ + fmt.Sprintf("GAIA_A_E2E_CHAIN_ID=%s", s.chainA.id), + fmt.Sprintf("GAIA_B_E2E_CHAIN_ID=%s", s.chainB.id), + fmt.Sprintf("GAIA_A_E2E_VAL_MNEMONIC=%s", gaiaAVal.mnemonic), + fmt.Sprintf("GAIA_B_E2E_VAL_MNEMONIC=%s", gaiaBVal.mnemonic), + fmt.Sprintf("GAIA_A_E2E_RLY_MNEMONIC=%s", gaiaARly.mnemonic), + fmt.Sprintf("GAIA_B_E2E_RLY_MNEMONIC=%s", gaiaBRly.mnemonic), + fmt.Sprintf("GAIA_A_E2E_VAL_HOST=%s", s.valResources[s.chainA.id][0].Container.Name[1:]), + fmt.Sprintf("GAIA_B_E2E_VAL_HOST=%s", s.valResources[s.chainB.id][0].Container.Name[1:]), + }, + User: "root", + Entrypoint: []string{ + "sh", + "-c", + "chmod +x /root/hermes/hermes_bootstrap.sh && /root/hermes/hermes_bootstrap.sh", + }, + }, + noRestart, + ) + s.Require().NoError(err) + // TODO: fix Hermes container REST endpoint + // endpoint := fmt.Sprintf("http://%s/state", s.hermesResource0.GetHostPort("3031/tcp")) + // s.Require().Eventually( + // func() bool { + // resp, err := http.Get(endpoint) //nolint:gosec // this is a test + // if err != nil { + // return false + // } + + // defer resp.Body.Close() + + // bz, err := io.ReadAll(resp.Body) + // if err != nil { + // return false + // } + + // var respBody map[string]interface{} + // if err := json.Unmarshal(bz, &respBody); err != nil { + // return false + // } + + // status := respBody["status"].(string) + // result := respBody["result"].(map[string]interface{}) + + // return status == "success" && len(result["chains"].([]interface{})) == 2 + // }, + // 5*time.Minute, + // time.Second, + // "hermes relayer not healthy", + // ) + + s.T().Logf("started Hermes relayer 0 container: %s", s.hermesResource0.Container.ID) + + // XXX: Give time to both networks to start, otherwise we might see gRPC + // transport errors. + time.Sleep(10 * time.Second) + + // create the client, connection and channel between the two Gaia chains + s.createConnection() + time.Sleep(10 * time.Second) + s.createChannel() +} + +// hermes1 is for bypass-msg test. Hermes1 is to process asynchronous transactions, +// Hermes1 has access to two Hermes configurations: one configuration allows paying fees, while the other does not. +// With Hermes1, better control can be achieved regarding whether fees are paid when clearing transactions. +func (s *IntegrationTestSuite) runIBCRelayer1() { + s.T().Log("starting Hermes relayer container 1...") + + tmpDir, err := os.MkdirTemp("", "gaia-e2e-testnet-hermes-") + s.Require().NoError(err) + s.tmpDirs = append(s.tmpDirs, tmpDir) + + gaiaAVal := s.chainA.validators[0] + gaiaBVal := s.chainB.validators[0] + + gaiaARly := s.chainA.genesisAccounts[relayerAccountIndexHermes1] + gaiaBRly := s.chainB.genesisAccounts[relayerAccountIndexHermes1] + + hermesCfgPath := path.Join(tmpDir, "hermes") + + s.Require().NoError(os.MkdirAll(hermesCfgPath, 0o755)) + _, err = copyFile( + filepath.Join("./scripts/", "hermes1_bootstrap.sh"), + filepath.Join(hermesCfgPath, "hermes1_bootstrap.sh"), + ) + s.Require().NoError(err) + + s.hermesResource1, err = s.dkrPool.RunWithOptions( + &dockertest.RunOptions{ + Name: fmt.Sprintf("%s-%s-relayer-1", s.chainA.id, s.chainB.id), + Repository: "ghcr.io/cosmos/hermes-e2e", + Tag: "1.4.1", + NetworkID: s.dkrNet.Network.ID, + Mounts: []string{ + fmt.Sprintf("%s/:/root/hermes", hermesCfgPath), + }, + PortBindings: map[docker.Port][]docker.PortBinding{ + "3032/tcp": {{HostIP: "", HostPort: "3032"}}, + }, + Env: []string{ + fmt.Sprintf("GAIA_A_E2E_CHAIN_ID=%s", s.chainA.id), + fmt.Sprintf("GAIA_B_E2E_CHAIN_ID=%s", s.chainB.id), + fmt.Sprintf("GAIA_A_E2E_VAL_MNEMONIC=%s", gaiaAVal.mnemonic), + fmt.Sprintf("GAIA_B_E2E_VAL_MNEMONIC=%s", gaiaBVal.mnemonic), + fmt.Sprintf("GAIA_A_E2E_RLY_MNEMONIC=%s", gaiaARly.mnemonic), + fmt.Sprintf("GAIA_B_E2E_RLY_MNEMONIC=%s", gaiaBRly.mnemonic), + fmt.Sprintf("GAIA_A_E2E_VAL_HOST=%s", s.valResources[s.chainA.id][0].Container.Name[1:]), + fmt.Sprintf("GAIA_B_E2E_VAL_HOST=%s", s.valResources[s.chainB.id][0].Container.Name[1:]), + }, + User: "root", + Entrypoint: []string{ + "sh", + "-c", + "chmod +x /root/hermes/hermes1_bootstrap.sh && /root/hermes/hermes1_bootstrap.sh && tail -f /dev/null", + }, + }, + noRestart, + ) + s.Require().NoError(err) + + s.T().Logf("started Hermes relayer 1 container: %s", s.hermesResource1.Container.ID) + + // XXX: Give time to both networks to start, otherwise we might see gRPC + // transport errors. + time.Sleep(10 * time.Second) +} + +func (s *IntegrationTestSuite) writeGovParamChangeProposalGlobalFees(c *chain, coins sdk.DecCoins) { + type ParamInfo struct { + Subspace string `json:"subspace"` + Key string `json:"key"` + Value sdk.DecCoins `json:"value"` + } + + type ParamChangeMessage struct { + Title string `json:"title"` + Description string `json:"description"` + Changes []ParamInfo `json:"changes"` + Deposit string `json:"deposit"` + } + + paramChangeProposalBody, err := json.MarshalIndent(ParamChangeMessage{ + Title: "global fee test", + Description: "global fee change", + Changes: []ParamInfo{ + { + Subspace: "globalfee", + Key: "MinimumGasPricesParam", + Value: coins, + }, + }, + Deposit: "1000uatom", + }, "", " ") + s.Require().NoError(err) + + err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalGlobalFeeFilename), paramChangeProposalBody) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) writeGovParamChangeProposalBypassMsgs(c *chain, msgs []string) { + type ParamInfo struct { + Subspace string `json:"subspace"` + Key string `json:"key"` + Value []string `json:"value"` + } + + type ParamChangeMessage struct { + Title string `json:"title"` + Description string `json:"description"` + Changes []ParamInfo `json:"changes"` + Deposit string `json:"deposit"` + } + paramChangeProposalBody, err := json.MarshalIndent(ParamChangeMessage{ + Title: "ChangeProposalBypassMsgs", + Description: "global fee change", + Changes: []ParamInfo{ + { + Subspace: "globalfee", + Key: "BypassMinFeeMsgTypes", + Value: msgs, + }, + }, + Deposit: "1000uatom", + }, "", " ") + s.Require().NoError(err) + + err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalBypassMsgFilename), paramChangeProposalBody) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) writeGovParamChangeProposalMaxTotalBypass(c *chain, gas uint64) { + type ParamInfo struct { + Subspace string `json:"subspace"` + Key string `json:"key"` + Value string `json:"value"` + } + + type ParamChangeMessage struct { + Title string `json:"title"` + Description string `json:"description"` + Changes []ParamInfo `json:"changes"` + Deposit string `json:"deposit"` + } + paramChangeProposalBody, err := json.MarshalIndent(ParamChangeMessage{ + Title: "ChangeProposalMaxTotalBypass", + Description: "global fee change", + Changes: []ParamInfo{ + { + Subspace: "globalfee", + Key: "MaxTotalBypassMinFeeMsgGasUsage", + Value: strconv.FormatInt(int64(gas), 10), + }, + }, + Deposit: "1000uatom", + }, "", " ") + s.Require().NoError(err) + + err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalMaxTotalBypassFilename), paramChangeProposalBody) + s.Require().NoError(err) +} + func (s *IntegrationTestSuite) writeGovCommunitySpendProposal(c *chain, amount sdk.Coin, recipient string) { msg := &distrtypes.MsgCommunityPoolSpend{ Authority: govModuleAddress, @@ -729,21 +910,6 @@ func (s *IntegrationTestSuite) writeGovLegProposal(c *chain, height int64, name s.Require().NoError(err) } -// func (s *IntegrationTestSuite) writeGovCommunitySpendProposal(c *chain, amount string, recipient string) { -// proposalCommSpend := &distrtypes.CommunityPoolSpendProposalWithDeposit{ -// Title: "Community Pool Spend", -// Description: "Fund Team!", -// Recipient: recipient, -// Amount: amount, -// Deposit: "1000uatom", -// } -// commSpendBody, err := json.MarshalIndent(proposalCommSpend, "", " ") -// s.Require().NoError(err) - -// err = writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalCommunitySpendFilename), commSpendBody) -// s.Require().NoError(err) -// } - // type ConsumerAdditionProposalWithDeposit struct { // ccvprovider.ConsumerAdditionProposal // Deposit string `json:"deposit"` diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index c6727543ef3..daf20a21a86 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -3,12 +3,12 @@ package e2e import "fmt" var ( - runBankTest = true - // runBypassMinFeeTest = true - runEncodeTest = true - runEvidenceTest = true - runFeeGrantTest = true - // runGlobalFeesTest = true + runBankTest = true + runBypassMinFeeTest = true + runEncodeTest = true + runEvidenceTest = true + runFeeGrantTest = true + runGlobalFeesTest = true runGovTest = true runIBCTest = true runSlashingTest = true @@ -31,13 +31,13 @@ func (s *IntegrationTestSuite) TestBank() { s.testBankTokenTransfer() } -// func (s *IntegrationTestSuite) TestByPassMinFee() { -// if !runBypassMinFeeTest { -// s.T().Skip() -// } -// chainAPI := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) -// s.testBypassMinFeeWithdrawReward(chainAPI) -// } +func (s *IntegrationTestSuite) TestByPassMinFee() { + if !runBypassMinFeeTest { + s.T().Skip() + } + chainAPI := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + s.testBypassMinFeeWithdrawReward(chainAPI) +} func (s *IntegrationTestSuite) TestEncode() { if !runEncodeTest { @@ -61,14 +61,13 @@ func (s *IntegrationTestSuite) TestFeeGrant() { s.testFeeGrant() } -// func (s *IntegrationTestSuite) TestGlobalFees() { -// if !runGlobalFeesTest { -// s.T().Skip() -// } -// s.testGlobalFees() -// s.testQueryGlobalFeesInGenesis() -// } -// +func (s *IntegrationTestSuite) TestGlobalFees() { + if !runGlobalFeesTest { + s.T().Skip() + } + s.testGlobalFees() + s.testQueryGlobalFeesInGenesis() +} func (s *IntegrationTestSuite) TestGov() { if !runGovTest { @@ -87,6 +86,11 @@ func (s *IntegrationTestSuite) TestIBC() { s.testIBCTokenTransfer() s.testMultihopIBCTokenTransfer() s.testFailedMultihopIBCTokenTransfer() + + // stop hermes0 to prevent hermes0 relaying transactions + s.Require().NoError(s.dkrPool.Purge(s.hermesResource0)) + HermesResource0Purged = true + s.testIBCBypassMsg() } func (s *IntegrationTestSuite) TestSlashing() { diff --git a/tests/e2e/query.go b/tests/e2e/query.go index 433385b1ff8..15d4e10aa4d 100644 --- a/tests/e2e/query.go +++ b/tests/e2e/query.go @@ -14,6 +14,8 @@ import ( disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/gaia/v11/x/globalfee/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -24,7 +26,6 @@ func queryGaiaTx(endpoint, txHash string) error { if err != nil { return fmt.Errorf("failed to execute HTTP request: %w", err) } - defer resp.Body.Close() if resp.StatusCode != 200 { @@ -37,6 +38,7 @@ func queryGaiaTx(endpoint, txHash string) error { } txResp := result["tx_response"].(map[string]interface{}) + if v := txResp["code"]; v.(float64) != 0 { return fmt.Errorf("tx %s failed with status code %v", txHash, v) } @@ -73,37 +75,37 @@ func queryGaiaAllBalances(endpoint, addr string) (sdk.Coins, error) { return balancesResp.Balances, nil } -// func queryGlobalFeeParams(endpoint string) (types.QueryParamsResponse, error) { -// body, err := httpGet(fmt.Sprintf("%s/gaia/globalfee/v1beta1/params", endpoint)) -// if err != nil { -// return types.QueryParamsResponse{}, fmt.Errorf("failed to execute HTTP request: %w", err) -// } +func queryGlobalFeeParams(endpoint string) (types.QueryParamsResponse, error) { + body, err := httpGet(fmt.Sprintf("%s/gaia/globalfee/v1beta1/params", endpoint)) + if err != nil { + return types.QueryParamsResponse{}, fmt.Errorf("failed to execute HTTP request: %w", err) + } -// var params types.QueryParamsResponse -// if err := cdc.UnmarshalJSON(body, ¶ms); err != nil { -// return types.QueryParamsResponse{}, err -// } + var params types.QueryParamsResponse + if err := cdc.UnmarshalJSON(body, ¶ms); err != nil { + return types.QueryParamsResponse{}, err + } -// return params, nil -// } + return params, nil +} -// func queryGlobalFees(endpoint string) (sdk.DecCoins, error) { -// p, err := queryGlobalFeeParams(endpoint) +func queryGlobalFees(endpoint string) (sdk.DecCoins, error) { + p, err := queryGlobalFeeParams(endpoint) -// return p.Params.MinimumGasPrices, err -// } + return p.Params.MinimumGasPrices, err +} -// func queryBypassMsgs(endpoint string) ([]string, error) { -// p, err := queryGlobalFeeParams(endpoint) +func queryBypassMsgs(endpoint string) ([]string, error) { + p, err := queryGlobalFeeParams(endpoint) -// return p.Params.BypassMinFeeMsgTypes, err -// } + return p.Params.BypassMinFeeMsgTypes, err +} -// func queryMaxTotalBypassMinFeeMsgGasUsage(endpoint string) (uint64, error) { -// p, err := queryGlobalFeeParams(endpoint) +func queryMaxTotalBypassMinFeeMsgGasUsage(endpoint string) (uint64, error) { + p, err := queryGlobalFeeParams(endpoint) -// return p.Params.MaxTotalBypassMinFeeMsgGasUsage, err -// } + return p.Params.MaxTotalBypassMinFeeMsgGasUsage, err +} func queryDelegation(endpoint string, validatorAddr string, delegatorAddr string) (stakingtypes.QueryDelegationResponse, error) { var res stakingtypes.QueryDelegationResponse @@ -133,7 +135,7 @@ func queryDelegatorWithdrawalAddress(endpoint string, delegatorAddr string) (dis return res, nil } -func queryDelegatorTotalRewards(endpoint, delegatorAddr string) (disttypes.QueryDelegationTotalRewardsResponse, error) { //nolint:unused +func queryDelegatorTotalRewards(endpoint, delegatorAddr string) (disttypes.QueryDelegationTotalRewardsResponse, error) { var res disttypes.QueryDelegationTotalRewardsResponse body, err := httpGet(fmt.Sprintf("%s/cosmos/distribution/v1beta1/delegators/%s/rewards", endpoint, delegatorAddr)) diff --git a/x/globalfee/alias.go b/x/globalfee/alias.go index 11458c0b8d3..594fce105e2 100644 --- a/x/globalfee/alias.go +++ b/x/globalfee/alias.go @@ -1,9 +1,9 @@ package globalfee -// import ( -// "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) +import ( + "github.com/cosmos/gaia/v11/x/globalfee/types" +) -// const ( -// ModuleName = types.ModuleName -// ) +const ( + ModuleName = types.ModuleName +) diff --git a/x/globalfee/ante/antetest/fee_test.go b/x/globalfee/ante/antetest/fee_test.go index 662bc61be5e..a94c4fc0f4d 100644 --- a/x/globalfee/ante/antetest/fee_test.go +++ b/x/globalfee/ante/antetest/fee_test.go @@ -1,815 +1,796 @@ package antetest -// import ( -// "testing" - -// cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" -// "github.com/cosmos/cosmos-sdk/testutil/testdata" -// sdk "github.com/cosmos/cosmos-sdk/types" -// stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -// ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" -// ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" -// "github.com/stretchr/testify/suite" - -// gaiafeeante "github.com/cosmos/gaia/v11/x/globalfee/ante" -// globfeetypes "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) - -// var testGasLimit uint64 = 200_000 - -// func TestIntegrationTestSuite(t *testing.T) { -// suite.Run(t, new(IntegrationTestSuite)) -// } - -// func (s *IntegrationTestSuite) TestGetDefaultGlobalFees() { -// // set globalfees and min gas price -// feeDecorator, _ := s.SetupTestGlobalFeeStoreAndMinGasPrice([]sdk.DecCoin{}, &globfeetypes.Params{}) -// defaultGlobalFees, err := feeDecorator.DefaultZeroGlobalFee(s.ctx) -// s.Require().NoError(err) -// s.Require().Greater(len(defaultGlobalFees), 0) - -// if defaultGlobalFees[0].Denom != testBondDenom { -// s.T().Fatalf("bond denom: %s, default global fee denom: %s", testBondDenom, defaultGlobalFees[0].Denom) -// } -// } - -// // Test global fees and min_gas_price with bypass msg types. -// // Please note even globalfee=0, min_gas_price=0, we do not let fee=0random_denom pass. -// // Paid fees are already sanitized by removing zero coins(through feeFlag parsing), so use sdk.NewCoins() to create it. -// func (s *IntegrationTestSuite) TestGlobalFeeMinimumGasFeeAnteHandler() { -// s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() -// priv1, _, addr1 := testdata.KeyTestPubAddr() -// privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - -// denominator := int64(100000) -// high := sdk.NewDec(400).Quo(sdk.NewDec(denominator)) // 0.004 -// med := sdk.NewDec(200).Quo(sdk.NewDec(denominator)) // 0.002 -// low := sdk.NewDec(100).Quo(sdk.NewDec(denominator)) // 0.001 - -// highFeeAmt := sdk.NewInt(high.MulInt64(int64(2) * denominator).RoundInt64()) -// medFeeAmt := sdk.NewInt(med.MulInt64(int64(2) * denominator).RoundInt64()) -// lowFeeAmt := sdk.NewInt(low.MulInt64(int64(2) * denominator).RoundInt64()) - -// globalfeeParamsEmpty := []sdk.DecCoin{} -// minGasPriceEmpty := []sdk.DecCoin{} -// globalfeeParams0 := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("photon", sdk.NewDec(0)), -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), -// } -// globalfeeParamsContain0 := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("photon", med), -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), -// } -// minGasPrice0 := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("stake", sdk.NewDec(0)), -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), -// } -// globalfeeParamsHigh := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("uatom", high), -// } -// minGasPrice := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("uatom", med), -// sdk.NewDecCoinFromDec("stake", med), -// } -// globalfeeParamsLow := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("uatom", low), -// } -// // global fee must be sorted in denom -// globalfeeParamsNewDenom := []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("photon", high), -// sdk.NewDecCoinFromDec("quark", high), -// } - -// testCases := map[string]struct { -// minGasPrice []sdk.DecCoin -// globalFee []sdk.DecCoin -// gasPrice sdk.Coins -// gasLimit sdk.Gas -// txMsg sdk.Msg -// txCheck bool -// expErr bool -// }{ -// // test fees -// // empty min_gas_price or empty global fee -// "empty min_gas_price, nonempty global fee, fee higher/equal than global_fee": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParamsHigh, -// // sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()) -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "empty min_gas_price, nonempty global fee, fee lower than global_fee": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParamsHigh, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "nonempty min_gas_price with defaultGlobalFee denom, empty global fee, fee higher/equal than min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsEmpty, // default 0uatom -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", medFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "nonempty min_gas_price with defaultGlobalFee denom, empty global fee, fee lower than min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "empty min_gas_price, empty global fee, empty fee": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.Coins{}, -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// // zero min_gas_price or zero global fee -// "zero min_gas_price, zero global fee, zero fee in global fee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt()), sdk.NewCoin("photon", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "zero min_gas_price, zero global fee, empty fee": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParams0, -// gasPrice: sdk.Coins{}, -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// // zero global fee -// "zero min_gas_price, zero global fee, zero fee not in globalfee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "zero min_gas_price, zero global fee, zero fees one in, one not in globalfee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins( -// sdk.NewCoin("stake", sdk.ZeroInt()), -// sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// // zero min_gas_price and empty global fee -// "zero min_gas_price, empty global fee, zero fee in min_gas_price_denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "zero min_gas_price, empty global fee, zero fee not in min_gas_price denom, not in defaultZeroGlobalFee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.NewCoins(sdk.NewCoin("quark", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "zero min_gas_price, empty global fee, zero fee in defaultZeroGlobalFee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "zero min_gas_price, empty global fee, nonzero fee in defaultZeroGlobalFee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "zero min_gas_price, empty global fee, nonzero fee not in defaultZeroGlobalFee denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsEmpty, -// gasPrice: sdk.NewCoins(sdk.NewCoin("quark", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// // empty min_gas_price, zero global fee -// "empty min_gas_price, zero global fee, zero fee in global fee denom": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "empty min_gas_price, zero global fee, zero fee not in global fee denom": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "empty min_gas_price, zero global fee, nonzero fee in global fee denom": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "empty min_gas_price, zero global fee, nonzero fee not in global fee denom": { -// minGasPrice: minGasPriceEmpty, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("stake", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// // zero min_gas_price, nonzero global fee -// "zero min_gas_price, nonzero global fee, fee is higher than global fee": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// // nonzero min_gas_price, nonzero global fee -// "fee higher/equal than globalfee and min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsHigh, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "fee lower than globalfee and min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsHigh, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "fee with one denom higher/equal, one denom lower than globalfee and min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsNewDenom, -// gasPrice: sdk.NewCoins( -// sdk.NewCoin("photon", lowFeeAmt), -// sdk.NewCoin("quark", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "globalfee > min_gas_price, fee higher/equal than min_gas_price, lower than globalfee": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsHigh, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", medFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "globalfee < min_gas_price, fee higher/equal than globalfee and lower than min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// // nonzero min_gas_price, zero global fee -// "nonzero min_gas_price, zero global fee, fee is in global fee denom and lower than min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "nonzero min_gas_price, zero global fee, fee is in global fee denom and higher/equal than min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", medFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "nonzero min_gas_price, zero global fee, fee is in min_gas_price denom which is not in global fee default, but higher/equal than min_gas_price": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParams0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("stake", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// // fee denom tests -// "min_gas_price denom is not subset of global fee denom , fee paying in global fee denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsNewDenom, -// gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "min_gas_price denom is not subset of global fee denom, fee paying in min_gas_price denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsNewDenom, -// gasPrice: sdk.NewCoins(sdk.NewCoin("stake", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "fees contain denom not in globalfee": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins( -// sdk.NewCoin("uatom", highFeeAmt), -// sdk.NewCoin("quark", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "fees contain denom not in globalfee with zero amount": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt), -// sdk.NewCoin("quark", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// // cases from https://github.com/cosmos/gaia/pull/1570#issuecomment-1190524402 -// // note: this is kind of a silly scenario but technically correct -// // if there is a zero coin in the globalfee, the user could pay 0fees -// // if the user includes any fee at all in the non-zero denom, it must be higher than that non-zero fee -// // unlikely we will ever see zero and non-zero together but technically possible -// "globalfee contains zero coin and non-zero coin, fee is lower than the nonzero coin": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsContain0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("photon", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "globalfee contains zero coin, fee contains zero coins of the same denom and a lower fee of the other denom in global fee": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsContain0, -// gasPrice: sdk.NewCoins( -// sdk.NewCoin("photon", lowFeeAmt), -// sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "globalfee contains zero coin, fee is empty": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsContain0, -// gasPrice: sdk.Coins{}, -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "globalfee contains zero coin, fee contains lower fee of zero coins's denom, globalfee also contains nonzero coin,fee contains higher fee of nonzero coins's denom, ": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsContain0, -// gasPrice: sdk.NewCoins( -// sdk.NewCoin("photon", lowFeeAmt), -// sdk.NewCoin("uatom", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "globalfee contains zero coin, fee is all zero coins but in global fee's denom": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsContain0, -// gasPrice: sdk.NewCoins( -// sdk.NewCoin("photon", sdk.ZeroInt()), -// sdk.NewCoin("uatom", sdk.ZeroInt()), -// ), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "globalfee contains zero coin, fee is higher than the nonzero coin": { -// minGasPrice: minGasPrice0, -// globalFee: globalfeeParamsContain0, -// gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "bypass msg type: ibc.core.channel.v1.MsgRecvPacket": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgRecvPacket( -// ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "bypass msg type: ibc.core.channel.v1.MsgTimeout": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgTimeout( -// // todo check here -// ibcchanneltypes.Packet{}, 1, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "bypass msg type: ibc.core.channel.v1.MsgTimeoutOnClose": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgTimeout( -// ibcchanneltypes.Packet{}, 2, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "bypass msg gas usage exceeds maxTotalBypassMinFeeMsgGasUsage": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: 2 * globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, -// txMsg: ibcchanneltypes.NewMsgTimeout( -// ibcchanneltypes.Packet{}, 2, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: true, -// }, -// "bypass msg gas usage equals to maxTotalBypassMinFeeMsgGasUsage": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, -// txMsg: ibcchanneltypes.NewMsgTimeout( -// ibcchanneltypes.Packet{}, 3, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "msg type ibc, zero fee not in globalfee denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("photon", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgRecvPacket( -// ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "msg type ibc, nonzero fee in globalfee denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgRecvPacket( -// ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "msg type ibc, nonzero fee not in globalfee denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgRecvPacket( -// ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: true, -// }, -// "msg type ibc, empty fee": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.Coins{}, -// gasLimit: testGasLimit, -// txMsg: ibcchanneltypes.NewMsgRecvPacket( -// ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// txCheck: true, -// expErr: false, -// }, -// "msg type non-ibc, nonzero fee in globalfee denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: false, -// }, -// "msg type non-ibc, empty fee": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.Coins{}, -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "msg type non-ibc, nonzero fee not in globalfee denom": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: true, -// expErr: true, -// }, -// "disable checkTx: min_gas_price is medium, global fee is low, tx fee is low": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: false, -// expErr: false, -// }, -// "disable checkTx: min_gas_price is medium, global fee is low, tx is zero": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: false, -// expErr: true, -// }, -// "disable checkTx: min_gas_price is low, global fee is low, tx fee's denom is not in global fees denoms set": { -// minGasPrice: minGasPrice, -// globalFee: globalfeeParamsLow, -// gasPrice: sdk.NewCoins(sdk.NewCoin("quark", sdk.ZeroInt())), -// gasLimit: testGasLimit, -// txMsg: testdata.NewTestMsg(addr1), -// txCheck: false, -// expErr: true, -// }, -// } - -// globalfeeParams := &globfeetypes.Params{ -// BypassMinFeeMsgTypes: globfeetypes.DefaultBypassMinFeeMsgTypes, -// MaxTotalBypassMinFeeMsgGasUsage: globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, -// } - -// for name, tc := range testCases { -// s.Run(name, func() { -// // set globalfees and min gas price -// globalfeeParams.MinimumGasPrices = tc.globalFee -// _, antehandler := s.SetupTestGlobalFeeStoreAndMinGasPrice(tc.minGasPrice, globalfeeParams) - -// // set fee decorator to ante handler - -// s.Require().NoError(s.txBuilder.SetMsgs(tc.txMsg)) -// s.txBuilder.SetFeeAmount(tc.gasPrice) -// s.txBuilder.SetGasLimit(tc.gasLimit) -// tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) -// s.Require().NoError(err) - -// s.ctx = s.ctx.WithIsCheckTx(tc.txCheck) -// _, err = antehandler(s.ctx, tx, false) -// if !tc.expErr { -// s.Require().NoError(err) -// } else { -// s.Require().Error(err) -// } -// }) -// } -// } - -// // Test how the operator fees are determined using various min gas prices. -// // -// // Note that in a real Gaia deployment all zero coins can be removed from minGasPrice. -// // This sanitizing happens when the minGasPrice is set into the context. -// // (see baseapp.SetMinGasPrices in gaia/cmd/root.go line 221) -// func (s *IntegrationTestSuite) TestGetMinGasPrice() { -// expCoins := sdk.Coins{ -// sdk.NewCoin("photon", sdk.NewInt(2000)), -// sdk.NewCoin("uatom", sdk.NewInt(3000)), -// } - -// testCases := []struct { -// name string -// minGasPrice []sdk.DecCoin -// feeTxGasLimit uint64 -// expCoins sdk.Coins -// }{ -// { -// "empty min gas price should return empty coins", -// []sdk.DecCoin{}, -// uint64(1000), -// sdk.Coins{}, -// }, -// { -// "zero coins min gas price should return empty coins", -// []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("stake", sdk.NewDec(0)), -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), -// }, -// uint64(1000), -// sdk.Coins{}, -// }, -// { -// "zero coins, non-zero coins mix should return zero coin and non-zero coins", -// []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("stake", sdk.NewDec(0)), -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(1)), -// }, -// uint64(1000), -// sdk.Coins{ -// sdk.NewCoin("stake", sdk.NewInt(0)), -// sdk.NewCoin("uatom", sdk.NewInt(1000)), -// }, -// }, - -// { -// "unsorted min gas price should return sorted coins", -// []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(3)), -// sdk.NewDecCoinFromDec("photon", sdk.NewDec(2)), -// }, -// uint64(1000), -// expCoins, -// }, -// { -// "sorted min gas price should return same conins", -// []sdk.DecCoin{ -// sdk.NewDecCoinFromDec("photon", sdk.NewDec(2)), -// sdk.NewDecCoinFromDec("uatom", sdk.NewDec(3)), -// }, -// uint64(1000), -// expCoins, -// }, -// } - -// for _, tc := range testCases { -// s.Run(tc.name, func() { -// s.SetupTestGlobalFeeStoreAndMinGasPrice(tc.minGasPrice, &globfeetypes.Params{}) - -// fees := gaiafeeante.GetMinGasPrice(s.ctx, int64(tc.feeTxGasLimit)) -// s.Require().True(tc.expCoins.Sort().IsEqual(fees)) -// }) -// } -// } - -// func (s *IntegrationTestSuite) TestContainsOnlyBypassMinFeeMsgs() { -// // set globalfees params and min gas price -// globalfeeParams := &globfeetypes.Params{ -// BypassMinFeeMsgTypes: globfeetypes.DefaultBypassMinFeeMsgTypes, -// MaxTotalBypassMinFeeMsgGasUsage: globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, -// } -// feeDecorator, _ := s.SetupTestGlobalFeeStoreAndMinGasPrice([]sdk.DecCoin{}, globalfeeParams) -// testCases := []struct { -// name string -// msgs []sdk.Msg -// expPass bool -// }{ -// { -// "expect empty msgs to pass", -// []sdk.Msg{}, -// true, -// }, -// { -// "expect default bypass msg to pass", -// []sdk.Msg{ -// ibcchanneltypes.NewMsgRecvPacket(ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// ibcchanneltypes.NewMsgAcknowledgement(ibcchanneltypes.Packet{}, []byte{1}, []byte{1}, ibcclienttypes.Height{}, ""), -// }, -// true, -// }, -// { -// "expect default bypass msgs to pass", -// []sdk.Msg{ -// ibcchanneltypes.NewMsgRecvPacket(ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// ibcchanneltypes.NewMsgAcknowledgement(ibcchanneltypes.Packet{}, []byte{1}, []byte{1}, ibcclienttypes.Height{}, ""), -// }, -// true, -// }, -// { -// "msgs contain non-bypass msg - should not pass", -// []sdk.Msg{ -// ibcchanneltypes.NewMsgRecvPacket(ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), -// stakingtypes.NewMsgDelegate(sdk.AccAddress{}, sdk.ValAddress{}, sdk.Coin{}), -// }, -// false, -// }, -// { -// "msgs contain only non-bypass msgs - should not pass", -// []sdk.Msg{ -// stakingtypes.NewMsgDelegate(sdk.AccAddress{}, sdk.ValAddress{}, sdk.Coin{}), -// }, -// false, -// }, -// } - -// for _, tc := range testCases { -// s.Run(tc.name, func() { -// res := feeDecorator.ContainsOnlyBypassMinFeeMsgs(s.ctx, tc.msgs) -// s.Require().True(tc.expPass == res) -// }) -// } -// } - -// func (s *IntegrationTestSuite) TestGetTxFeeRequired() { -// // create global fee params -// globalfeeParamsEmpty := &globfeetypes.Params{MinimumGasPrices: []sdk.DecCoin{}} - -// // setup tests with default global fee i.e. "0uatom" and empty local min gas prices -// feeDecorator, _ := s.SetupTestGlobalFeeStoreAndMinGasPrice([]sdk.DecCoin{}, globalfeeParamsEmpty) - -// // set a subspace that doesn't have the stakingtypes.KeyBondDenom key registred -// feeDecorator.StakingSubspace = s.app.GetSubspace(globfeetypes.ModuleName) - -// // check that an error is returned when staking bond denom is empty -// _, err := feeDecorator.GetTxFeeRequired(s.ctx, nil) -// s.Require().Equal(err.Error(), "empty staking bond denomination") - -// // set non-zero local min gas prices -// localMinGasPrices := sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1))) - -// // setup tests with non-empty local min gas prices -// feeDecorator, _ = s.SetupTestGlobalFeeStoreAndMinGasPrice( -// sdk.NewDecCoinsFromCoins(localMinGasPrices...), -// globalfeeParamsEmpty, -// ) - -// // mock tx data -// s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() -// priv1, _, addr1 := testdata.KeyTestPubAddr() -// privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - -// s.Require().NoError(s.txBuilder.SetMsgs(testdata.NewTestMsg(addr1))) -// s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt()))) - -// s.txBuilder.SetGasLimit(uint64(1)) -// tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) -// s.Require().NoError(err) - -// // check that the required fees returned in CheckTx mode are equal to -// // local min gas prices since they're greater than the default global fee values. -// s.Require().True(s.ctx.IsCheckTx()) -// res, err := feeDecorator.GetTxFeeRequired(s.ctx, tx) -// s.Require().True(res.IsEqual(localMinGasPrices)) -// s.Require().NoError(err) - -// // check that the global fee is returned in DeliverTx mode. -// globalFee, err := feeDecorator.GetGlobalFee(s.ctx, tx) -// s.Require().NoError(err) - -// ctx := s.ctx.WithIsCheckTx(false) -// res, err = feeDecorator.GetTxFeeRequired(ctx, tx) -// s.Require().NoError(err) -// s.Require().True(res.IsEqual(globalFee)) -// } +import ( + "testing" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/stretchr/testify/suite" + + gaiafeeante "github.com/cosmos/gaia/v11/x/globalfee/ante" + globfeetypes "github.com/cosmos/gaia/v11/x/globalfee/types" +) + +var testGasLimit uint64 = 200_000 + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} + +func (s *IntegrationTestSuite) TestGetDefaultGlobalFees() { + // set globalfees and min gas price + feeDecorator, _ := s.SetupTestGlobalFeeStoreAndMinGasPrice([]sdk.DecCoin{}, &globfeetypes.Params{}) + defaultGlobalFees, err := feeDecorator.DefaultZeroGlobalFee(s.ctx) + s.Require().NoError(err) + s.Require().Greater(len(defaultGlobalFees), 0) + + if defaultGlobalFees[0].Denom != testBondDenom { + s.T().Fatalf("bond denom: %s, default global fee denom: %s", testBondDenom, defaultGlobalFees[0].Denom) + } +} + +// Test global fees and min_gas_price with bypass msg types. +// Please note even globalfee=0, min_gas_price=0, we do not let fee=0random_denom pass. +// Paid fees are already sanitized by removing zero coins(through feeFlag parsing), so use sdk.NewCoins() to create it. +func (s *IntegrationTestSuite) TestGlobalFeeMinimumGasFeeAnteHandler() { + s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() + priv1, _, addr1 := testdata.KeyTestPubAddr() + privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} + + denominator := int64(100000) + high := sdk.NewDec(400).Quo(sdk.NewDec(denominator)) // 0.004 + med := sdk.NewDec(200).Quo(sdk.NewDec(denominator)) // 0.002 + low := sdk.NewDec(100).Quo(sdk.NewDec(denominator)) // 0.001 + + highFeeAmt := sdk.NewInt(high.MulInt64(int64(2) * denominator).RoundInt64()) + medFeeAmt := sdk.NewInt(med.MulInt64(int64(2) * denominator).RoundInt64()) + lowFeeAmt := sdk.NewInt(low.MulInt64(int64(2) * denominator).RoundInt64()) + + globalfeeParamsEmpty := []sdk.DecCoin{} + minGasPriceEmpty := []sdk.DecCoin{} + globalfeeParams0 := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("photon", sdk.NewDec(0)), + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), + } + globalfeeParamsContain0 := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("photon", med), + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), + } + minGasPrice0 := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("stake", sdk.NewDec(0)), + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), + } + globalfeeParamsHigh := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("uatom", high), + } + minGasPrice := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("uatom", med), + sdk.NewDecCoinFromDec("stake", med), + } + globalfeeParamsLow := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("uatom", low), + } + // global fee must be sorted in denom + globalfeeParamsNewDenom := []sdk.DecCoin{ + sdk.NewDecCoinFromDec("photon", high), + sdk.NewDecCoinFromDec("quark", high), + } + + testCases := map[string]struct { + minGasPrice []sdk.DecCoin + globalFee []sdk.DecCoin + gasPrice sdk.Coins + gasLimit sdk.Gas + txMsg sdk.Msg + txCheck bool + expErr bool + }{ + // test fees + // empty min_gas_price or empty global fee + "empty min_gas_price, nonempty global fee, fee higher/equal than global_fee": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParamsHigh, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "empty min_gas_price, nonempty global fee, fee lower than global_fee": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParamsHigh, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "nonempty min_gas_price with defaultGlobalFee denom, empty global fee, fee higher/equal than min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsEmpty, // default 0uatom + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", medFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "nonempty min_gas_price with defaultGlobalFee denom, empty global fee, fee lower than min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "empty min_gas_price, empty global fee, empty fee": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.Coins{}, + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + // zero min_gas_price or zero global fee + "zero min_gas_price, zero global fee, zero fee in global fee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt()), sdk.NewCoin("photon", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "zero min_gas_price, zero global fee, empty fee": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParams0, + gasPrice: sdk.Coins{}, + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + // zero global fee + "zero min_gas_price, zero global fee, zero fee not in globalfee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "zero min_gas_price, zero global fee, zero fees one in, one not in globalfee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins( + sdk.NewCoin("stake", sdk.ZeroInt()), + sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + // zero min_gas_price and empty global fee + "zero min_gas_price, empty global fee, zero fee in min_gas_price_denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "zero min_gas_price, empty global fee, zero fee not in min_gas_price denom, not in defaultZeroGlobalFee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.NewCoins(sdk.NewCoin("quark", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "zero min_gas_price, empty global fee, zero fee in defaultZeroGlobalFee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "zero min_gas_price, empty global fee, nonzero fee in defaultZeroGlobalFee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "zero min_gas_price, empty global fee, nonzero fee not in defaultZeroGlobalFee denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsEmpty, + gasPrice: sdk.NewCoins(sdk.NewCoin("quark", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + // empty min_gas_price, zero global fee + "empty min_gas_price, zero global fee, zero fee in global fee denom": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "empty min_gas_price, zero global fee, zero fee not in global fee denom": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "empty min_gas_price, zero global fee, nonzero fee in global fee denom": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "empty min_gas_price, zero global fee, nonzero fee not in global fee denom": { + minGasPrice: minGasPriceEmpty, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("stake", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + // zero min_gas_price, nonzero global fee + "zero min_gas_price, nonzero global fee, fee is higher than global fee": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + // nonzero min_gas_price, nonzero global fee + "fee higher/equal than globalfee and min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsHigh, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "fee lower than globalfee and min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsHigh, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "fee with one denom higher/equal, one denom lower than globalfee and min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsNewDenom, + gasPrice: sdk.NewCoins( + sdk.NewCoin("photon", lowFeeAmt), + sdk.NewCoin("quark", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "globalfee > min_gas_price, fee higher/equal than min_gas_price, lower than globalfee": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsHigh, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", medFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "globalfee < min_gas_price, fee higher/equal than globalfee and lower than min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + // nonzero min_gas_price, zero global fee + "nonzero min_gas_price, zero global fee, fee is in global fee denom and lower than min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "nonzero min_gas_price, zero global fee, fee is in global fee denom and higher/equal than min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", medFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "nonzero min_gas_price, zero global fee, fee is in min_gas_price denom which is not in global fee default, but higher/equal than min_gas_price": { + minGasPrice: minGasPrice, + globalFee: globalfeeParams0, + gasPrice: sdk.NewCoins(sdk.NewCoin("stake", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + // fee denom tests + "min_gas_price denom is not subset of global fee denom , fee paying in global fee denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsNewDenom, + gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "min_gas_price denom is not subset of global fee denom, fee paying in min_gas_price denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsNewDenom, + gasPrice: sdk.NewCoins(sdk.NewCoin("stake", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "fees contain denom not in globalfee": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins( + sdk.NewCoin("uatom", highFeeAmt), + sdk.NewCoin("quark", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "fees contain denom not in globalfee with zero amount": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt), + sdk.NewCoin("quark", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + // cases from https://github.com/cosmos/gaia/pull/1570#issuecomment-1190524402 + // note: this is kind of a silly scenario but technically correct + // if there is a zero coin in the globalfee, the user could pay 0fees + // if the user includes any fee at all in the non-zero denom, it must be higher than that non-zero fee + // unlikely we will ever see zero and non-zero together but technically possible + "globalfee contains zero coin and non-zero coin, fee is lower than the nonzero coin": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsContain0, + gasPrice: sdk.NewCoins(sdk.NewCoin("photon", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "globalfee contains zero coin, fee contains zero coins of the same denom and a lower fee of the other denom in global fee": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsContain0, + gasPrice: sdk.NewCoins( + sdk.NewCoin("photon", lowFeeAmt), + sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "globalfee contains zero coin, fee is empty": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsContain0, + gasPrice: sdk.Coins{}, + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "globalfee contains zero coin, fee contains lower fee of zero coins's denom, globalfee also contains nonzero coin,fee contains higher fee of nonzero coins's denom, ": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsContain0, + gasPrice: sdk.NewCoins( + sdk.NewCoin("photon", lowFeeAmt), + sdk.NewCoin("uatom", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "globalfee contains zero coin, fee is all zero coins but in global fee's denom": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsContain0, + gasPrice: sdk.NewCoins( + sdk.NewCoin("photon", sdk.ZeroInt()), + sdk.NewCoin("uatom", sdk.ZeroInt()), + ), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "globalfee contains zero coin, fee is higher than the nonzero coin": { + minGasPrice: minGasPrice0, + globalFee: globalfeeParamsContain0, + gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "bypass msg type: ibc.core.channel.v1.MsgRecvPacket": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "bypass msg type: ibc.core.channel.v1.MsgTimeout": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgTimeout( + // todo check here + ibcchanneltypes.Packet{}, 1, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "bypass msg type: ibc.core.channel.v1.MsgTimeoutOnClose": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgTimeout( + ibcchanneltypes.Packet{}, 2, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "bypass msg gas usage exceeds maxTotalBypassMinFeeMsgGasUsage": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: 2 * globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, + txMsg: ibcchanneltypes.NewMsgTimeout( + ibcchanneltypes.Packet{}, 2, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: true, + }, + "bypass msg gas usage equals to maxTotalBypassMinFeeMsgGasUsage": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, + txMsg: ibcchanneltypes.NewMsgTimeout( + ibcchanneltypes.Packet{}, 3, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "msg type ibc, zero fee not in globalfee denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("photon", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "msg type ibc, nonzero fee in globalfee denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "msg type ibc, nonzero fee not in globalfee denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: true, + }, + "msg type ibc, empty fee": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.Coins{}, + gasLimit: testGasLimit, + txMsg: ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + txCheck: true, + expErr: false, + }, + "msg type non-ibc, nonzero fee in globalfee denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: false, + }, + "msg type non-ibc, empty fee": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.Coins{}, + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "msg type non-ibc, nonzero fee not in globalfee denom": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("photon", highFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: true, + expErr: true, + }, + "disable checkTx: min_gas_price is medium, global fee is low, tx fee is low": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", lowFeeAmt)), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: false, + expErr: false, + }, + "disable checkTx: min_gas_price is medium, global fee is low, tx is zero": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: false, + expErr: true, + }, + "disable checkTx: min_gas_price is low, global fee is low, tx fee's denom is not in global fees denoms set": { + minGasPrice: minGasPrice, + globalFee: globalfeeParamsLow, + gasPrice: sdk.NewCoins(sdk.NewCoin("quark", sdk.ZeroInt())), + gasLimit: testGasLimit, + txMsg: testdata.NewTestMsg(addr1), + txCheck: false, + expErr: true, + }, + } + + globalfeeParams := &globfeetypes.Params{ + BypassMinFeeMsgTypes: globfeetypes.DefaultBypassMinFeeMsgTypes, + MaxTotalBypassMinFeeMsgGasUsage: globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, + } + + for name, tc := range testCases { + s.Run(name, func() { + // set globalfees and min gas price + globalfeeParams.MinimumGasPrices = tc.globalFee + _, antehandler := s.SetupTestGlobalFeeStoreAndMinGasPrice(tc.minGasPrice, globalfeeParams) + + // set fee decorator to ante handler + + s.Require().NoError(s.txBuilder.SetMsgs(tc.txMsg)) + s.txBuilder.SetFeeAmount(tc.gasPrice) + s.txBuilder.SetGasLimit(tc.gasLimit) + tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) + s.Require().NoError(err) + + s.ctx = s.ctx.WithIsCheckTx(tc.txCheck) + _, err = antehandler(s.ctx, tx, false) + if !tc.expErr { + s.Require().NoError(err) + } else { + s.Require().Error(err) + } + }) + } +} + +// Test how the operator fees are determined using various min gas prices. +// +// Note that in a real Gaia deployment all zero coins can be removed from minGasPrice. +// This sanitizing happens when the minGasPrice is set into the context. +// (see baseapp.SetMinGasPrices in gaia/cmd/root.go line 221) +func (s *IntegrationTestSuite) TestGetMinGasPrice() { + expCoins := sdk.Coins{ + sdk.NewCoin("photon", sdk.NewInt(2000)), + sdk.NewCoin("uatom", sdk.NewInt(3000)), + } + + testCases := []struct { + name string + minGasPrice []sdk.DecCoin + feeTxGasLimit uint64 + expCoins sdk.Coins + }{ + { + "empty min gas price should return empty coins", + []sdk.DecCoin{}, + uint64(1000), + sdk.Coins{}, + }, + { + "zero coins min gas price should return empty coins", + []sdk.DecCoin{ + sdk.NewDecCoinFromDec("stake", sdk.NewDec(0)), + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(0)), + }, + uint64(1000), + sdk.Coins{}, + }, + { + "zero coins, non-zero coins mix should return zero coin and non-zero coins", + []sdk.DecCoin{ + sdk.NewDecCoinFromDec("stake", sdk.NewDec(0)), + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(1)), + }, + uint64(1000), + sdk.Coins{ + sdk.NewCoin("stake", sdk.NewInt(0)), + sdk.NewCoin("uatom", sdk.NewInt(1000)), + }, + }, + + { + "unsorted min gas price should return sorted coins", + []sdk.DecCoin{ + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(3)), + sdk.NewDecCoinFromDec("photon", sdk.NewDec(2)), + }, + uint64(1000), + expCoins, + }, + { + "sorted min gas price should return same conins", + []sdk.DecCoin{ + sdk.NewDecCoinFromDec("photon", sdk.NewDec(2)), + sdk.NewDecCoinFromDec("uatom", sdk.NewDec(3)), + }, + uint64(1000), + expCoins, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.SetupTestGlobalFeeStoreAndMinGasPrice(tc.minGasPrice, &globfeetypes.Params{}) + + fees := gaiafeeante.GetMinGasPrice(s.ctx, int64(tc.feeTxGasLimit)) + s.Require().True(tc.expCoins.Sort().IsEqual(fees)) + }) + } +} + +func (s *IntegrationTestSuite) TestContainsOnlyBypassMinFeeMsgs() { + // set globalfees params and min gas price + globalfeeParams := &globfeetypes.Params{ + BypassMinFeeMsgTypes: globfeetypes.DefaultBypassMinFeeMsgTypes, + MaxTotalBypassMinFeeMsgGasUsage: globfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage, + } + feeDecorator, _ := s.SetupTestGlobalFeeStoreAndMinGasPrice([]sdk.DecCoin{}, globalfeeParams) + testCases := []struct { + name string + msgs []sdk.Msg + expPass bool + }{ + { + "expect empty msgs to pass", + []sdk.Msg{}, + true, + }, + { + "expect default bypass msg to pass", + []sdk.Msg{ + ibcchanneltypes.NewMsgRecvPacket(ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + ibcchanneltypes.NewMsgAcknowledgement(ibcchanneltypes.Packet{}, []byte{1}, []byte{1}, ibcclienttypes.Height{}, ""), + }, + true, + }, + { + "msgs contain not only bypass msg - should not pass", + []sdk.Msg{ + ibcchanneltypes.NewMsgRecvPacket(ibcchanneltypes.Packet{}, nil, ibcclienttypes.Height{}, ""), + stakingtypes.NewMsgDelegate(sdk.AccAddress{}, sdk.ValAddress{}, sdk.Coin{}), + }, + false, + }, + { + "msgs contain only non-bypass msgs - should not pass", + []sdk.Msg{ + stakingtypes.NewMsgDelegate(sdk.AccAddress{}, sdk.ValAddress{}, sdk.Coin{}), + }, + false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + res := feeDecorator.ContainsOnlyBypassMinFeeMsgs(s.ctx, tc.msgs) + s.Require().True(tc.expPass == res) + }) + } +} + +func (s *IntegrationTestSuite) TestGetTxFeeRequired() { + // create global fee params + globalfeeParamsEmpty := &globfeetypes.Params{MinimumGasPrices: []sdk.DecCoin{}} + + // set non-zero local min gas prices + localMinGasPrices := sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1))) + + // setup tests with non-empty local min gas prices + feeDecorator, _ := s.SetupTestGlobalFeeStoreAndMinGasPrice( + sdk.NewDecCoinsFromCoins(localMinGasPrices...), + globalfeeParamsEmpty, + ) + + // mock tx data + s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() + priv1, _, addr1 := testdata.KeyTestPubAddr() + privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} + + s.Require().NoError(s.txBuilder.SetMsgs(testdata.NewTestMsg(addr1))) + s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("uatom", sdk.ZeroInt()))) + + s.txBuilder.SetGasLimit(uint64(1)) + tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) + s.Require().NoError(err) + + // check that the required fees returned in CheckTx mode are equal to + // local min gas prices since they're greater than the default global fee values. + s.Require().True(s.ctx.IsCheckTx()) + res, err := feeDecorator.GetTxFeeRequired(s.ctx, tx) + s.Require().True(res.IsEqual(localMinGasPrices)) + s.Require().NoError(err) + + // check that the global fee is returned in DeliverTx mode. + globalFee, err := feeDecorator.GetGlobalFee(s.ctx, tx) + s.Require().NoError(err) + + ctx := s.ctx.WithIsCheckTx(false) + res, err = feeDecorator.GetTxFeeRequired(ctx, tx) + s.Require().NoError(err) + s.Require().True(res.IsEqual(globalFee)) +} diff --git a/x/globalfee/ante/antetest/fee_test_setup.go b/x/globalfee/ante/antetest/fee_test_setup.go index f0c89043485..0cc44507963 100644 --- a/x/globalfee/ante/antetest/fee_test_setup.go +++ b/x/globalfee/ante/antetest/fee_test_setup.go @@ -1,125 +1,120 @@ package antetest -// import ( -// "fmt" - -// "github.com/cosmos/cosmos-sdk/client" -// "github.com/cosmos/cosmos-sdk/client/tx" -// cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" -// "github.com/cosmos/cosmos-sdk/testutil/testdata" -// sdk "github.com/cosmos/cosmos-sdk/types" -// "github.com/cosmos/cosmos-sdk/types/tx/signing" -// xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" -// "github.com/cosmos/cosmos-sdk/x/params/types" -// stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -// "github.com/stretchr/testify/suite" -// tmrand "github.com/tendermint/tendermint/libs/rand" -// tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - -// gaiahelpers "github.com/cosmos/gaia/v11/app/helpers" -// gaiafeeante "github.com/cosmos/gaia/v11/x/globalfee/ante" - -// gaiaapp "github.com/cosmos/gaia/v11/app" -// "github.com/cosmos/gaia/v11/x/globalfee" -// globfeetypes "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) - -// type IntegrationTestSuite struct { -// suite.Suite - -// app *gaiaapp.GaiaApp -// ctx sdk.Context -// clientCtx client.Context -// txBuilder client.TxBuilder -// } - -// var testBondDenom = "uatom" - -// func (s *IntegrationTestSuite) SetupTest() { -// app := gaiahelpers.Setup(s.T()) -// ctx := app.BaseApp.NewContext(false, tmproto.Header{ -// ChainID: fmt.Sprintf("test-chain-%s", tmrand.Str(4)), -// Height: 1, -// }) - -// encodingConfig := gaiaapp.MakeTestEncodingConfig() -// encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) -// testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry) - -// s.app = app -// s.ctx = ctx -// s.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig) -// } - -// func (s *IntegrationTestSuite) SetupTestGlobalFeeStoreAndMinGasPrice(minGasPrice []sdk.DecCoin, globalFeeParams *globfeetypes.Params) (gaiafeeante.FeeDecorator, sdk.AnteHandler) { -// subspace := s.app.GetSubspace(globalfee.ModuleName) -// subspace.SetParamSet(s.ctx, globalFeeParams) -// s.ctx = s.ctx.WithMinGasPrices(minGasPrice).WithIsCheckTx(true) - -// // set staking params -// stakingParam := stakingtypes.DefaultParams() -// stakingParam.BondDenom = testBondDenom -// stakingSubspace := s.SetupTestStakingSubspace(stakingParam) - -// // build fee decorator -// feeDecorator := gaiafeeante.NewFeeDecorator(subspace, stakingSubspace) - -// // chain fee decorator to antehandler -// antehandler := sdk.ChainAnteDecorators(feeDecorator) - -// return feeDecorator, antehandler -// } - -// // SetupTestStakingSubspace sets uatom as bond denom for the fee tests. -// func (s *IntegrationTestSuite) SetupTestStakingSubspace(params stakingtypes.Params) types.Subspace { -// s.app.GetSubspace(stakingtypes.ModuleName).SetParamSet(s.ctx, ¶ms) -// return s.app.GetSubspace(stakingtypes.ModuleName) -// } - -// func (s *IntegrationTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, error) { -// var sigsV2 []signing.SignatureV2 -// for i, priv := range privs { -// sigV2 := signing.SignatureV2{ -// PubKey: priv.PubKey(), -// Data: &signing.SingleSignatureData{ -// SignMode: s.clientCtx.TxConfig.SignModeHandler().DefaultMode(), -// Signature: nil, -// }, -// Sequence: accSeqs[i], -// } - -// sigsV2 = append(sigsV2, sigV2) -// } - -// if err := s.txBuilder.SetSignatures(sigsV2...); err != nil { -// return nil, err -// } - -// sigsV2 = []signing.SignatureV2{} -// for i, priv := range privs { -// signerData := xauthsigning.SignerData{ -// ChainID: chainID, -// AccountNumber: accNums[i], -// Sequence: accSeqs[i], -// } -// sigV2, err := tx.SignWithPrivKey( -// s.clientCtx.TxConfig.SignModeHandler().DefaultMode(), -// signerData, -// s.txBuilder, -// priv, -// s.clientCtx.TxConfig, -// accSeqs[i], -// ) -// if err != nil { -// return nil, err -// } - -// sigsV2 = append(sigsV2, sigV2) -// } - -// if err := s.txBuilder.SetSignatures(sigsV2...); err != nil { -// return nil, err -// } - -// return s.txBuilder.GetTx(), nil -// } +import ( + "fmt" + + tmrand "github.com/cometbft/cometbft/libs/rand" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/stretchr/testify/suite" + + gaiahelpers "github.com/cosmos/gaia/v11/app/helpers" + gaiaparams "github.com/cosmos/gaia/v11/app/params" + gaiafeeante "github.com/cosmos/gaia/v11/x/globalfee/ante" + + gaiaapp "github.com/cosmos/gaia/v11/app" + "github.com/cosmos/gaia/v11/x/globalfee" + globfeetypes "github.com/cosmos/gaia/v11/x/globalfee/types" +) + +type IntegrationTestSuite struct { + suite.Suite + + app *gaiaapp.GaiaApp + ctx sdk.Context + clientCtx client.Context + txBuilder client.TxBuilder +} + +var testBondDenom = "uatom" + +func (s *IntegrationTestSuite) SetupTest() { + app := gaiahelpers.Setup(s.T()) + ctx := app.BaseApp.NewContext(false, tmproto.Header{ + ChainID: fmt.Sprintf("test-chain-%s", tmrand.Str(4)), + Height: 1, + }) + + encodingConfig := gaiaparams.MakeEncodingConfig() + encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) + testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry) + + s.app = app + s.ctx = ctx + s.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig) +} + +func (s *IntegrationTestSuite) SetupTestGlobalFeeStoreAndMinGasPrice(minGasPrice []sdk.DecCoin, globalFeeParams *globfeetypes.Params) (gaiafeeante.FeeDecorator, sdk.AnteHandler) { + subspace := s.app.GetSubspace(globalfee.ModuleName) + subspace.SetParamSet(s.ctx, globalFeeParams) + s.ctx = s.ctx.WithMinGasPrices(minGasPrice).WithIsCheckTx(true) + + // setup staking bond denom to "uatom" + // since it's "stake" per default + params := s.app.StakingKeeper.GetParams(s.ctx) + params.BondDenom = testBondDenom + err := s.app.StakingKeeper.SetParams(s.ctx, params) + s.Require().NoError(err) + + // build fee decorator + feeDecorator := gaiafeeante.NewFeeDecorator(subspace, s.app.StakingKeeper) + + // chain fee decorator to antehandler + antehandler := sdk.ChainAnteDecorators(feeDecorator) + + return feeDecorator, antehandler +} + +func (s *IntegrationTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, error) { + var sigsV2 []signing.SignatureV2 + for i, priv := range privs { + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: s.clientCtx.TxConfig.SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: accSeqs[i], + } + + sigsV2 = append(sigsV2, sigV2) + } + + if err := s.txBuilder.SetSignatures(sigsV2...); err != nil { + return nil, err + } + + sigsV2 = []signing.SignatureV2{} + for i, priv := range privs { + signerData := xauthsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + sigV2, err := tx.SignWithPrivKey( + s.clientCtx.TxConfig.SignModeHandler().DefaultMode(), + signerData, + s.txBuilder, + priv, + s.clientCtx.TxConfig, + accSeqs[i], + ) + if err != nil { + return nil, err + } + + sigsV2 = append(sigsV2, sigV2) + } + + if err := s.txBuilder.SetSignatures(sigsV2...); err != nil { + return nil, err + } + + return s.txBuilder.GetTx(), nil +} diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 81969e3f857..af09e2a2d82 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -1,278 +1,284 @@ package ante -// import ( -// "errors" -// "fmt" +import ( + "errors" + "fmt" -// errorsmod "cosmossdk.io/errors" -// sdk "github.com/cosmos/cosmos-sdk/types" -// paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -// stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -// gaiaerrors "github.com/cosmos/gaia/v11/types/errors" -// tmstrings "github.com/tendermint/tendermint/libs/strings" + errorsmod "cosmossdk.io/errors" + tmstrings "github.com/cometbft/cometbft/libs/strings" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -// "github.com/cosmos/gaia/v11/x/globalfee" -// "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + + gaiaerrors "github.com/cosmos/gaia/v11/types/errors" + + "github.com/cosmos/gaia/v11/x/globalfee" + "github.com/cosmos/gaia/v11/x/globalfee/types" +) // FeeWithBypassDecorator checks if the transaction's fee is at least as large // as the local validator's minimum gasFee (defined in validator config) and global fee, and the fee denom should be in the global fees' denoms. // -// import ( -// "errors" -// "fmt" // // CONTRACT: Tx must implement FeeTx to use FeeDecorator // If the tx msg type is one of the bypass msg types, the tx is valid even if the min fee is lower than normally required. // If the bypass tx still carries fees, the fee denom should be the same as global fee required. -// var _ sdk.AnteDecorator = FeeDecorator{} +var _ sdk.AnteDecorator = FeeDecorator{} -// type FeeDecorator struct { -// GlobalMinFeeParamSource globalfee.ParamSource -// StakingSubspace paramtypes.Subspace -// } +type FeeDecorator struct { + GlobalMinFeeParamSource globalfee.ParamSource + StakingKeeper *stakingkeeper.Keeper +} -// func NewFeeDecorator(globalfeeSubspace, stakingSubspace paramtypes.Subspace) FeeDecorator { -// if !globalfeeSubspace.HasKeyTable() { -// panic("global fee paramspace was not set up via module") -// } +func NewFeeDecorator(globalfeeSubspace paramtypes.Subspace, sk *stakingkeeper.Keeper) FeeDecorator { + if !globalfeeSubspace.HasKeyTable() { + panic("global fee paramspace was not set up via module") + } -// if !stakingSubspace.HasKeyTable() { -// panic("staking paramspace was not set up via module") -// } - -// return FeeDecorator{ -// GlobalMinFeeParamSource: globalfeeSubspace, -// StakingSubspace: stakingSubspace, -// } -// } + return FeeDecorator{ + GlobalMinFeeParamSource: globalfeeSubspace, + StakingKeeper: sk, + } +} // AnteHandle implements the AnteDecorator interface -// func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { -// feeTx, ok := tx.(sdk.FeeTx) -// if !ok { -// return ctx, errorsmod.Wrap(gaiaerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") -// } - -// // Do not check minimum-gas-prices and global fees during simulations -// if simulate { -// return next(ctx, tx, simulate) -// } - -// // Get the required fees according to the CheckTx or DeliverTx modes -// feeRequired, err := mfd.GetTxFeeRequired(ctx, feeTx) -// if err != nil { -// return ctx, err -// } - -// reject the transaction early if the feeCoins have more denoms than the fee requirement - -// feeRequired cannot be empty -// if feeTx.GetFee().Len() > feeRequired.Len() { -// return ctx, errorsmod.Wrapf(gaiaerrors.ErrInvalidCoins, "fee is not a subset of required fees; got %s, required: %s", feeTx.GetFee().String(), feeRequired.String()) -// } - -// // Sort fee tx's coins, zero coins in feeCoins are already removed -// feeCoins := feeTx.GetFee().Sort() -// gas := feeTx.GetGas() -// msgs := feeTx.GetMsgs() - -// // split feeRequired into zero and non-zero coins(nonZeroCoinFeesReq, zeroCoinFeesDenomReq), split feeCoins according to -// // nonZeroCoinFeesReq, zeroCoinFeesDenomReq, -// // so that feeCoins can be checked separately against them. -// nonZeroCoinFeesReq, zeroCoinFeesDenomReq := getNonZeroFees(feeRequired) - -// // feeCoinsNonZeroDenom contains non-zero denominations from the feeRequired -// // feeCoinsNonZeroDenom is used to check if the fees meets the requirement imposed by nonZeroCoinFeesReq -// // when feeCoins does not contain zero coins' denoms in feeRequired -// feeCoinsNonZeroDenom, feeCoinsZeroDenom := splitCoinsByDenoms(feeCoins, zeroCoinFeesDenomReq) - -// Check that the fees are in expected denominations. -// according to splitCoinsByDenoms(), feeCoinsZeroDenom must be in denom subset of zeroCoinFeesDenomReq. -// check if feeCoinsNonZeroDenom is a subset of nonZeroCoinFeesReq. -// special case: if feeCoinsNonZeroDenom=[], DenomsSubsetOf returns true -// special case: if feeCoinsNonZeroDenom is not empty, but nonZeroCoinFeesReq empty, return false -// if !feeCoinsNonZeroDenom.DenomsSubsetOf(nonZeroCoinFeesReq) { -// return ctx, errorsmod.Wrapf(gaiaerrors.ErrInsufficientFee, "fee is not a subset of required fees; got %s, required: %s", feeCoins.String(), feeRequired.String()) -// } - -// // If the feeCoins pass the denoms check, check they are bypass-msg types. -// // -// // Bypass min fee requires: -// // - the tx contains only message types that can bypass the minimum fee, -// // see BypassMinFeeMsgTypes; -// // - the total gas limit per message does not exceed MaxTotalBypassMinFeeMsgGasUsage, -// // i.e., totalGas <= MaxTotalBypassMinFeeMsgGasUsage -// // Otherwise, minimum fees and global fees are checked to prevent spam. -// maxTotalBypassMinFeeMsgGasUsage := mfd.GetMaxTotalBypassMinFeeMsgGasUsage(ctx) -// doesNotExceedMaxGasUsage := gas <= maxTotalBypassMinFeeMsgGasUsage -// allBypassMsgs := mfd.ContainsOnlyBypassMinFeeMsgs(ctx, msgs) -// allowedToBypassMinFee := allBypassMsgs && doesNotExceedMaxGasUsage - -// if allowedToBypassMinFee { -// return next(ctx, tx, simulate) -// } - -// if the msg does not satisfy bypass condition and the feeCoins denoms are subset of feeRequired, -// check the feeCoins amount against feeRequired -// -// when feeCoins=[] -// special case: and there is zero coin in fee requirement, pass, -// otherwise, err -// if len(feeCoins) == 0 { -// if len(zeroCoinFeesDenomReq) != 0 { -// return next(ctx, tx, simulate) -// } -// return ctx, errorsmod.Wrapf(gaiaerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins.String(), feeRequired.String()) -// } - -// // when feeCoins != [] -// // special case: if TX has at least one of the zeroCoinFeesDenomReq, then it should pass -// if len(feeCoinsZeroDenom) > 0 { -// return next(ctx, tx, simulate) -// } - -// // After all the checks, the tx is confirmed: -// // feeCoins denoms subset off feeRequired -// // Not bypass -// // feeCoins != [] -// // Not contain zeroCoinFeesDenomReq's denoms -// // -// // check if the feeCoins's feeCoinsNonZeroDenom part has coins' amount higher/equal to nonZeroCoinFeesReq -// if !feeCoinsNonZeroDenom.IsAnyGTE(nonZeroCoinFeesReq) { -// errMsg := fmt.Sprintf("Insufficient fees; got: %s required: %s", feeCoins.String(), feeRequired.String()) -// if allBypassMsgs && !doesNotExceedMaxGasUsage { -// errMsg = fmt.Sprintf("Insufficient fees; bypass-min-fee-msg-types with gas consumption %v exceeds the maximum allowed gas value of %v.", gas, maxTotalBypassMinFeeMsgGasUsage) -// } - -// return ctx, errorsmod.Wrap(gaiaerrors.ErrInsufficientFee, errMsg) -// } - -// return next(ctx, tx, simulate) -// } - -// // GetTxFeeRequired returns the required fees for the given FeeTx. -// // In case the FeeTx's mode is CheckTx, it returns the combined requirements -// // of local min gas prices and global fees. Otherwise, in DeliverTx, it returns the global fee. -// func (mfd FeeDecorator) GetTxFeeRequired(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coins, error) { -// // Get required global fee min gas prices -// // Note that it should never be empty since its default value is set to coin={"StakingBondDenom", 0} -// globalFees, err := mfd.GetGlobalFee(ctx, tx) -// if err != nil { -// return sdk.Coins{}, err -// } - -// // In DeliverTx, the global fee min gas prices are the only tx fee requirements. -// if !ctx.IsCheckTx() { -// return globalFees, nil -// } - -// // In CheckTx mode, the local and global fee min gas prices are combined -// // to form the tx fee requirements - -// // Get local minimum-gas-prices -// localFees := GetMinGasPrice(ctx, int64(tx.GetGas())) - -// // Return combined fee requirements -// return CombinedFeeRequirement(globalFees, localFees) -// } - -// // GetGlobalFee returns the global fees for a given fee tx's gas -// // (might also return 0denom if globalMinGasPrice is 0) -// // sorted in ascending order. -// // Note that ParamStoreKeyMinGasPrices type requires coins sorted. -// func (mfd FeeDecorator) GetGlobalFee(ctx sdk.Context, feeTx sdk.FeeTx) (sdk.Coins, error) { -// var ( -// globalMinGasPrices sdk.DecCoins -// err error -// ) - -// if mfd.GlobalMinFeeParamSource.Has(ctx, types.ParamStoreKeyMinGasPrices) { -// mfd.GlobalMinFeeParamSource.Get(ctx, types.ParamStoreKeyMinGasPrices, &globalMinGasPrices) -// } -// // global fee is empty set, set global fee to 0uatom -// if len(globalMinGasPrices) == 0 { -// globalMinGasPrices, err = mfd.DefaultZeroGlobalFee(ctx) -// if err != nil { -// return sdk.Coins{}, err -// } -// } -// requiredGlobalFees := make(sdk.Coins, len(globalMinGasPrices)) -// // Determine the required fees by multiplying each required minimum gas -// // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). -// glDec := sdk.NewDec(int64(feeTx.GetGas())) -// for i, gp := range globalMinGasPrices { -// fee := gp.Amount.Mul(glDec) -// requiredGlobalFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) -// } - -// return requiredGlobalFees.Sort(), nil -// } - -// // DefaultZeroGlobalFee returns a zero coin with the staking module bond denom -// func (mfd FeeDecorator) DefaultZeroGlobalFee(ctx sdk.Context) ([]sdk.DecCoin, error) { -// bondDenom := mfd.getBondDenom(ctx) -// if bondDenom == "" { -// return nil, errors.New("empty staking bond denomination") -// } - -// return []sdk.DecCoin{sdk.NewDecCoinFromDec(bondDenom, sdk.NewDec(0))}, nil -// } - -// func (mfd FeeDecorator) getBondDenom(ctx sdk.Context) (bondDenom string) { -// if mfd.StakingSubspace.Has(ctx, stakingtypes.KeyBondDenom) { -// mfd.StakingSubspace.Get(ctx, stakingtypes.KeyBondDenom, &bondDenom) -// } - -// return -// } - -// func (mfd FeeDecorator) ContainsOnlyBypassMinFeeMsgs(ctx sdk.Context, msgs []sdk.Msg) bool { -// bypassMsgTypes := mfd.GetBypassMsgTypes(ctx) -// for _, msg := range msgs { -// if tmstrings.StringInSlice(sdk.MsgTypeURL(msg), bypassMsgTypes) { -// continue -// } -// return false -// } - -// return true -// } - -// func (mfd FeeDecorator) GetBypassMsgTypes(ctx sdk.Context) (res []string) { -// if mfd.GlobalMinFeeParamSource.Has(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes) { -// mfd.GlobalMinFeeParamSource.Get(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes, &res) -// } - -// return -// } - -// func (mfd FeeDecorator) GetMaxTotalBypassMinFeeMsgGasUsage(ctx sdk.Context) (res uint64) { -// if mfd.GlobalMinFeeParamSource.Has(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage) { -// mfd.GlobalMinFeeParamSource.Get(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &res) -// } - -// return -// } - -// // GetMinGasPrice returns a nodes's local minimum gas prices -// // fees given a gas limit -// func GetMinGasPrice(ctx sdk.Context, gasLimit int64) sdk.Coins { -// minGasPrices := ctx.MinGasPrices() -// // special case: if minGasPrices=[], requiredFees=[] -// if minGasPrices.IsZero() { -// return sdk.Coins{} -// } - -// 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 := sdk.NewDec(gasLimit) -// for i, gp := range minGasPrices { -// fee := gp.Amount.Mul(glDec) -// requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) -// } - -// return requiredFees.Sort() -// } +func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, errorsmod.Wrap(gaiaerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") + } + + // Do not check minimum-gas-prices and global fees during simulations + if simulate { + return next(ctx, tx, simulate) + } + + // Get the required fees according to the CheckTx or DeliverTx modes + feeRequired, err := mfd.GetTxFeeRequired(ctx, feeTx) + if err != nil { + return ctx, err + } + + ctx.Logger().Info(fmt.Sprintf("FeeCoins: %v", feeTx.GetFee())) + ctx.Logger().Info(fmt.Sprintf("FeeRequired: %v", feeRequired)) + + // reject the transaction early if the feeCoins have more denoms than the fee requirement + + // feeRequired cannot be empty + if feeTx.GetFee().Len() > feeRequired.Len() { + return ctx, errorsmod.Wrapf(gaiaerrors.ErrInvalidCoins, "fee is not a subset of required fees; got %s, required: %s", feeTx.GetFee().String(), feeRequired.String()) + } + + // Sort fee tx's coins, zero coins in feeCoins are already removed + feeCoins := feeTx.GetFee().Sort() + gas := feeTx.GetGas() + msgs := feeTx.GetMsgs() + + // split feeRequired into zero and non-zero coins(nonZeroCoinFeesReq, zeroCoinFeesDenomReq), split feeCoins according to + // nonZeroCoinFeesReq, zeroCoinFeesDenomReq, + // so that feeCoins can be checked separately against them. + nonZeroCoinFeesReq, zeroCoinFeesDenomReq := getNonZeroFees(feeRequired) + + // feeCoinsNonZeroDenom contains non-zero denominations from the feeRequired + // feeCoinsNonZeroDenom is used to check if the fees meets the requirement imposed by nonZeroCoinFeesReq + // when feeCoins does not contain zero coins' denoms in feeRequired + feeCoinsNonZeroDenom, feeCoinsZeroDenom := splitCoinsByDenoms(feeCoins, zeroCoinFeesDenomReq) + + // Check that the fees are in expected denominations. + // according to splitCoinsByDenoms(), feeCoinsZeroDenom must be in denom subset of zeroCoinFeesDenomReq. + // check if feeCoinsNonZeroDenom is a subset of nonZeroCoinFeesReq. + // special case: if feeCoinsNonZeroDenom=[], DenomsSubsetOf returns true + // special case: if feeCoinsNonZeroDenom is not empty, but nonZeroCoinFeesReq empty, return false + if !feeCoinsNonZeroDenom.DenomsSubsetOf(nonZeroCoinFeesReq) { + return ctx, errorsmod.Wrapf(gaiaerrors.ErrInsufficientFee, "fee is not a subset of required fees; got %s, required: %s", feeCoins.String(), feeRequired.String()) + } + + // If the feeCoins pass the denoms check, check they are bypass-msg types. + // + // Bypass min fee requires: + // - the tx contains only message types that can bypass the minimum fee, + // see BypassMinFeeMsgTypes; + // - the total gas limit per message does not exceed MaxTotalBypassMinFeeMsgGasUsage, + // i.e., totalGas <= MaxTotalBypassMinFeeMsgGasUsage + // Otherwise, minimum fees and global fees are checked to prevent spam. + maxTotalBypassMinFeeMsgGasUsage := mfd.GetMaxTotalBypassMinFeeMsgGasUsage(ctx) + doesNotExceedMaxGasUsage := gas <= maxTotalBypassMinFeeMsgGasUsage + allBypassMsgs := mfd.ContainsOnlyBypassMinFeeMsgs(ctx, msgs) + allowedToBypassMinFee := allBypassMsgs && doesNotExceedMaxGasUsage + ctx.Logger().Info(fmt.Sprintf("gas: %v", gas)) + ctx.Logger().Info(fmt.Sprintf("allBypassMsgs: %v", allBypassMsgs)) + ctx.Logger().Info(fmt.Sprintf("maxTotalBypassMinFeeMsgGasUsage: %v", maxTotalBypassMinFeeMsgGasUsage)) + ctx.Logger().Info(fmt.Sprintf("doesNotExceedMaxGasUsage: %v", doesNotExceedMaxGasUsage)) + ctx.Logger().Info(fmt.Sprintf("allowedToBypassMinFee: %v", allowedToBypassMinFee)) + + if allowedToBypassMinFee { + ctx.Logger().Info("Pass allowedToBypassMinFee check") + return next(ctx, tx, simulate) + } + + // if the msg does not satisfy bypass condition and the feeCoins denoms are subset of feeRequired, + // check the feeCoins amount against feeRequired + + // when feeCoins=[] + // special case: and there is zero coin in fee requirement, pass, + // otherwise, err + if len(feeCoins) == 0 { + if len(zeroCoinFeesDenomReq) != 0 { + return next(ctx, tx, simulate) + } + return ctx, errorsmod.Wrapf(gaiaerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins.String(), feeRequired.String()) + } + + // when feeCoins != [] + // special case: if TX has at least one of the zeroCoinFeesDenomReq, then it should pass + if len(feeCoinsZeroDenom) > 0 { + return next(ctx, tx, simulate) + } + + // After all the checks, the tx is confirmed: + // feeCoins denoms subset off feeRequired + // Not bypass + // feeCoins != [] + // Not contain zeroCoinFeesDenomReq's denoms + // + // check if the feeCoins's feeCoinsNonZeroDenom part has coins' amount higher/equal to nonZeroCoinFeesReq + if !feeCoinsNonZeroDenom.IsAnyGTE(nonZeroCoinFeesReq) { + errMsg := fmt.Sprintf("Insufficient fees; got: %s required: %s", feeCoins.String(), feeRequired.String()) + if allBypassMsgs && !doesNotExceedMaxGasUsage { + errMsg = fmt.Sprintf("Insufficient fees; bypass-min-fee-msg-types with gas consumption %v exceeds the maximum allowed gas value of %v.", gas, maxTotalBypassMinFeeMsgGasUsage) + } + + return ctx, errorsmod.Wrap(gaiaerrors.ErrInsufficientFee, errMsg) + } + + return next(ctx, tx, simulate) +} + +// GetTxFeeRequired returns the required fees for the given FeeTx. +// In case the FeeTx's mode is CheckTx, it returns the combined requirements +// of local min gas prices and global fees. Otherwise, in DeliverTx, it returns the global fee. +func (mfd FeeDecorator) GetTxFeeRequired(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coins, error) { + // Get required global fee min gas prices + // Note that it should never be empty since its default value is set to coin={"StakingBondDenom", 0} + globalFees, err := mfd.GetGlobalFee(ctx, tx) + if err != nil { + return sdk.Coins{}, err + } + + ctx.Logger().Info(fmt.Sprintf("GlobalFees: %v, IsCheckTx: %v", globalFees, ctx.IsCheckTx())) + + // In DeliverTx, the global fee min gas prices are the only tx fee requirements. + if !ctx.IsCheckTx() { + return globalFees, nil + } + + // In CheckTx mode, the local and global fee min gas prices are combined + // to form the tx fee requirements + + // Get local minimum-gas-prices + localFees := GetMinGasPrice(ctx, int64(tx.GetGas())) + ctx.Logger().Info(fmt.Sprintf("localFees: %v, IsCheckTx: %v", localFees, ctx.IsCheckTx())) + + c, err := CombinedFeeRequirement(globalFees, localFees) + ctx.Logger().Info(fmt.Sprintf("CombinedFeeRequirement: %v, IsCheckTx: %v", c, ctx.IsCheckTx())) + + // Return combined fee requirements + return c, err +} + +// GetGlobalFee returns the global fees for a given fee tx's gas +// (might also return 0denom if globalMinGasPrice is 0) +// sorted in ascending order. +// Note that ParamStoreKeyMinGasPrices type requires coins sorted. +func (mfd FeeDecorator) GetGlobalFee(ctx sdk.Context, feeTx sdk.FeeTx) (sdk.Coins, error) { + var ( + globalMinGasPrices sdk.DecCoins + err error + ) + + if mfd.GlobalMinFeeParamSource.Has(ctx, types.ParamStoreKeyMinGasPrices) { + mfd.GlobalMinFeeParamSource.Get(ctx, types.ParamStoreKeyMinGasPrices, &globalMinGasPrices) + } + // global fee is empty set, set global fee to 0uatom + if len(globalMinGasPrices) == 0 { + globalMinGasPrices, err = mfd.DefaultZeroGlobalFee(ctx) + if err != nil { + return sdk.Coins{}, err + } + } + requiredGlobalFees := make(sdk.Coins, len(globalMinGasPrices)) + // Determine the required fees by multiplying each required minimum gas + // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). + glDec := sdk.NewDec(int64(feeTx.GetGas())) + for i, gp := range globalMinGasPrices { + fee := gp.Amount.Mul(glDec) + requiredGlobalFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + + return requiredGlobalFees.Sort(), nil +} + +// DefaultZeroGlobalFee returns a zero coin with the staking module bond denom +func (mfd FeeDecorator) DefaultZeroGlobalFee(ctx sdk.Context) ([]sdk.DecCoin, error) { + bondDenom := mfd.StakingKeeper.BondDenom(ctx) + if bondDenom == "" { + return nil, errors.New("empty staking bond denomination") + } + + return []sdk.DecCoin{sdk.NewDecCoinFromDec(bondDenom, sdk.NewDec(0))}, nil +} + +func (mfd FeeDecorator) ContainsOnlyBypassMinFeeMsgs(ctx sdk.Context, msgs []sdk.Msg) bool { + bypassMsgTypes := mfd.GetBypassMsgTypes(ctx) + ctx.Logger().Info(fmt.Sprintf("BypassMsgs: %v", bypassMsgTypes)) + + for _, msg := range msgs { + ctx.Logger().Info(fmt.Sprintf("TxBypassMsg: %v", sdk.MsgTypeURL(msg))) + + if tmstrings.StringInSlice(sdk.MsgTypeURL(msg), bypassMsgTypes) { + continue + } + return false + } + + return true +} + +func (mfd FeeDecorator) GetBypassMsgTypes(ctx sdk.Context) (res []string) { + if mfd.GlobalMinFeeParamSource.Has(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes) { + mfd.GlobalMinFeeParamSource.Get(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes, &res) + } + + return +} + +func (mfd FeeDecorator) GetMaxTotalBypassMinFeeMsgGasUsage(ctx sdk.Context) (res uint64) { + if mfd.GlobalMinFeeParamSource.Has(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage) { + mfd.GlobalMinFeeParamSource.Get(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &res) + } + + return +} + +// GetMinGasPrice returns a nodes's local minimum gas prices +// fees given a gas limit +func GetMinGasPrice(ctx sdk.Context, gasLimit int64) sdk.Coins { + minGasPrices := ctx.MinGasPrices() + // special case: if minGasPrices=[], requiredFees=[] + if minGasPrices.IsZero() { + return sdk.Coins{} + } + + 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 := sdk.NewDec(gasLimit) + for i, gp := range minGasPrices { + fee := gp.Amount.Mul(glDec) + requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + + return requiredFees.Sort() +} diff --git a/x/globalfee/ante/fee_utils.go b/x/globalfee/ante/fee_utils.go index 27c5fb3899d..fa132e1d8b8 100644 --- a/x/globalfee/ante/fee_utils.go +++ b/x/globalfee/ante/fee_utils.go @@ -1,114 +1,115 @@ package ante -// import ( -// errorsmod "cosmossdk.io/errors" -// sdk "github.com/cosmos/cosmos-sdk/types" -// gaiaerrors "github.com/cosmos/gaia/v11/types/errors" -// ) +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + + gaiaerrors "github.com/cosmos/gaia/v11/types/errors" +) // ContainZeroCoins returns true if the given coins are empty or contain zero coins, // Note that the coins denoms must be validated, see sdk.ValidateDenom -// func ContainZeroCoins(coins sdk.Coins) bool { -// if len(coins) == 0 { -// return true -// } -// for _, coin := range coins { -// if coin.IsZero() { -// return true -// } -// } - -// return false -// } +func ContainZeroCoins(coins sdk.Coins) bool { + if len(coins) == 0 { + return true + } + for _, coin := range coins { + if coin.IsZero() { + return true + } + } + + return false +} // CombinedFeeRequirement returns the global fee and min_gas_price combined and sorted. // Both globalFees and minGasPrices must be valid, but CombinedFeeRequirement // does not validate them, so it may return 0denom. // if globalfee is empty, CombinedFeeRequirement return sdk.Coins{} -// func CombinedFeeRequirement(globalFees, minGasPrices sdk.Coins) (sdk.Coins, error) { -// // global fees should never be empty -// // since it has a default value using the staking module's bond denom -// if len(globalFees) == 0 { -// return sdk.Coins{}, errorsmod.Wrapf(gaiaerrors.ErrNotFound, "global fee cannot be empty") -// } - -// // empty min_gas_price -// if len(minGasPrices) == 0 { -// return globalFees, nil -// } - -// // if min_gas_price denom is in globalfee, and the amount is higher than globalfee, add min_gas_price to allFees -// var allFees sdk.Coins -// for _, fee := range globalFees { -// // min_gas_price denom in global fee -// ok, c := Find(minGasPrices, fee.Denom) -// if ok && c.Amount.GT(fee.Amount) { -// allFees = append(allFees, c) -// } else { -// allFees = append(allFees, fee) -// } -// } - -// return allFees.Sort(), nil -// } - -// // Find replaces the functionality of Coins.Find from SDK v0.46.x -// func Find(coins sdk.Coins, denom string) (bool, sdk.Coin) { -// switch len(coins) { -// case 0: -// return false, sdk.Coin{} - -// case 1: -// coin := coins[0] -// if coin.Denom == denom { -// return true, coin -// } -// return false, sdk.Coin{} - -// default: -// midIdx := len(coins) / 2 // 2:1, 3:1, 4:2 -// coin := coins[midIdx] -// switch { -// case denom < coin.Denom: -// return Find(coins[:midIdx], denom) -// case denom == coin.Denom: -// return true, coin -// default: -// return Find(coins[midIdx+1:], denom) -// } -// } -// } - -// // splitCoinsByDenoms returns the given coins split in two whether -// // their demon is or isn't found in the given denom map. -// func splitCoinsByDenoms(feeCoins sdk.Coins, denomMap map[string]struct{}) (sdk.Coins, sdk.Coins) { -// feeCoinsNonZeroDenom, feeCoinsZeroDenom := sdk.Coins{}, sdk.Coins{} - -// for _, fc := range feeCoins { -// _, found := denomMap[fc.Denom] -// if found { -// feeCoinsZeroDenom = append(feeCoinsZeroDenom, fc) -// } else { -// feeCoinsNonZeroDenom = append(feeCoinsNonZeroDenom, fc) -// } -// } - -// return feeCoinsNonZeroDenom.Sort(), feeCoinsZeroDenom.Sort() -// } - -// // getNonZeroFees returns the given fees nonzero coins -// // and a map storing the zero coins's denoms -// func getNonZeroFees(fees sdk.Coins) (sdk.Coins, map[string]struct{}) { -// requiredFeesNonZero := sdk.Coins{} -// requiredFeesZeroDenom := map[string]struct{}{} - -// for _, gf := range fees { -// if gf.IsZero() { -// requiredFeesZeroDenom[gf.Denom] = struct{}{} -// } else { -// requiredFeesNonZero = append(requiredFeesNonZero, gf) -// } -// } - -// return requiredFeesNonZero.Sort(), requiredFeesZeroDenom -// } +func CombinedFeeRequirement(globalFees, minGasPrices sdk.Coins) (sdk.Coins, error) { + // global fees should never be empty + // since it has a default value using the staking module's bond denom + if len(globalFees) == 0 { + return sdk.Coins{}, errorsmod.Wrapf(gaiaerrors.ErrNotFound, "global fee cannot be empty") + } + + // empty min_gas_price + if len(minGasPrices) == 0 { + return globalFees, nil + } + + // if min_gas_price denom is in globalfee, and the amount is higher than globalfee, add min_gas_price to allFees + var allFees sdk.Coins + for _, fee := range globalFees { + // min_gas_price denom in global fee + ok, c := Find(minGasPrices, fee.Denom) + if ok && c.Amount.GT(fee.Amount) { + allFees = append(allFees, c) + } else { + allFees = append(allFees, fee) + } + } + + return allFees.Sort(), nil +} + +// Find replaces the functionality of Coins.Find from SDK v0.46.x +func Find(coins sdk.Coins, denom string) (bool, sdk.Coin) { + switch len(coins) { + case 0: + return false, sdk.Coin{} + + case 1: + coin := coins[0] + if coin.Denom == denom { + return true, coin + } + return false, sdk.Coin{} + + default: + midIdx := len(coins) / 2 // 2:1, 3:1, 4:2 + coin := coins[midIdx] + switch { + case denom < coin.Denom: + return Find(coins[:midIdx], denom) + case denom == coin.Denom: + return true, coin + default: + return Find(coins[midIdx+1:], denom) + } + } +} + +// splitCoinsByDenoms returns the given coins split in two whether +// their demon is or isn't found in the given denom map. +func splitCoinsByDenoms(feeCoins sdk.Coins, denomMap map[string]struct{}) (sdk.Coins, sdk.Coins) { + feeCoinsNonZeroDenom, feeCoinsZeroDenom := sdk.Coins{}, sdk.Coins{} + + for _, fc := range feeCoins { + _, found := denomMap[fc.Denom] + if found { + feeCoinsZeroDenom = append(feeCoinsZeroDenom, fc) + } else { + feeCoinsNonZeroDenom = append(feeCoinsNonZeroDenom, fc) + } + } + + return feeCoinsNonZeroDenom.Sort(), feeCoinsZeroDenom.Sort() +} + +// getNonZeroFees returns the given fees nonzero coins +// and a map storing the zero coins's denoms +func getNonZeroFees(fees sdk.Coins) (sdk.Coins, map[string]struct{}) { + requiredFeesNonZero := sdk.Coins{} + requiredFeesZeroDenom := map[string]struct{}{} + + for _, gf := range fees { + if gf.IsZero() { + requiredFeesZeroDenom[gf.Denom] = struct{}{} + } else { + requiredFeesNonZero = append(requiredFeesNonZero, gf) + } + } + + return requiredFeesNonZero.Sort(), requiredFeesZeroDenom +} diff --git a/x/globalfee/ante/fee_utils_test.go b/x/globalfee/ante/fee_utils_test.go index 3b887003cb3..8378e467135 100644 --- a/x/globalfee/ante/fee_utils_test.go +++ b/x/globalfee/ante/fee_utils_test.go @@ -1,299 +1,298 @@ package ante -// -// import ( -// "testing" -// -// sdk "github.com/cosmos/cosmos-sdk/types" -// "github.com/stretchr/testify/require" -//) -// -// func TestContainZeroCoins(t *testing.T) { -// zeroCoin1 := sdk.NewCoin("photon", sdk.ZeroInt()) -// zeroCoin2 := sdk.NewCoin("stake", sdk.ZeroInt()) -// coin1 := sdk.NewCoin("photon", sdk.NewInt(1)) -// coin2 := sdk.NewCoin("stake", sdk.NewInt(2)) -// coin3 := sdk.NewCoin("quark", sdk.NewInt(3)) -// // coins must be valid !!! -// coinsEmpty := sdk.Coins{} -// coinsNonEmpty := sdk.Coins{coin1, coin2} -// coinsCointainZero := sdk.Coins{coin1, zeroCoin2} -// coinsCointainTwoZero := sdk.Coins{zeroCoin1, zeroCoin2, coin3} -// coinsAllZero := sdk.Coins{zeroCoin1, zeroCoin2} -// -// tests := []struct { -// c sdk.Coins -// ok bool -// }{ -// { -// coinsEmpty, -// true, -// }, -// { -// coinsNonEmpty, -// false, -// }, -// { -// coinsCointainZero, -// true, -// }, -// { -// coinsCointainTwoZero, -// true, -// }, -// { -// coinsAllZero, -// true, -// }, -// } -// -// for _, test := range tests { -// ok := ContainZeroCoins(test.c) -// require.Equal(t, test.ok, ok) -// } -//} -// -//// Note that in a real Gaia deployment all zero coins can be removed from minGasPrice. -//// This sanitizing happens when the minGasPrice is set into the context. -//// (see baseapp.SetMinGasPrices in gaia/cmd/root.go line 221) -// func TestCombinedFeeRequirement(t *testing.T) { -// zeroCoin1 := sdk.NewCoin("photon", sdk.ZeroInt()) -// zeroCoin2 := sdk.NewCoin("stake", sdk.ZeroInt()) -// zeroCoin3 := sdk.NewCoin("quark", sdk.ZeroInt()) -// coin1 := sdk.NewCoin("photon", sdk.NewInt(1)) -// coin2 := sdk.NewCoin("stake", sdk.NewInt(2)) -// coin1High := sdk.NewCoin("photon", sdk.NewInt(10)) -// coin2High := sdk.NewCoin("stake", sdk.NewInt(20)) -// coinNewDenom1 := sdk.NewCoin("Newphoton", sdk.NewInt(1)) -// coinNewDenom2 := sdk.NewCoin("Newstake", sdk.NewInt(1)) -// // coins must be valid !!! and sorted!!! -// coinsEmpty := sdk.Coins{} -// coinsNonEmpty := sdk.Coins{coin1, coin2}.Sort() -// coinsNonEmptyHigh := sdk.Coins{coin1High, coin2High}.Sort() -// coinsNonEmptyOneHigh := sdk.Coins{coin1High, coin2}.Sort() -// coinsNewDenom := sdk.Coins{coinNewDenom1, coinNewDenom2}.Sort() -// coinsNewOldDenom := sdk.Coins{coin1, coinNewDenom1}.Sort() -// coinsNewOldDenomHigh := sdk.Coins{coin1High, coinNewDenom1}.Sort() -// coinsCointainZero := sdk.Coins{coin1, zeroCoin2}.Sort() -// coinsCointainZeroNewDenom := sdk.Coins{coin1, zeroCoin3}.Sort() -// coinsAllZero := sdk.Coins{zeroCoin1, zeroCoin2}.Sort() -// tests := map[string]struct { -// cGlobal sdk.Coins -// c sdk.Coins -// combined sdk.Coins -// }{ -// "global fee invalid, return combined fee empty and non-nil error": { -// cGlobal: coinsEmpty, -// c: coinsEmpty, -// combined: coinsEmpty, -// }, -// "global fee nonempty, min fee empty, combined fee = global fee": { -// cGlobal: coinsNonEmpty, -// c: coinsNonEmpty, -// combined: coinsNonEmpty, -// }, -// "global fee and min fee have overlapping denom, min fees amounts are all higher": { -// cGlobal: coinsNonEmpty, -// c: coinsNonEmptyHigh, -// combined: coinsNonEmptyHigh, -// }, -// "global fee and min fee have overlapping denom, one of min fees amounts is higher": { -// cGlobal: coinsNonEmpty, -// c: coinsNonEmptyOneHigh, -// combined: coinsNonEmptyOneHigh, -// }, -// "global fee and min fee have no overlapping denom, combined fee = global fee": { -// cGlobal: coinsNonEmpty, -// c: coinsNewDenom, -// combined: coinsNonEmpty, -// }, -// "global fees and min fees have partial overlapping denom, min fee amount <= global fee amount, combined fees = global fees": { -// cGlobal: coinsNonEmpty, -// c: coinsNewOldDenom, -// combined: coinsNonEmpty, -// }, -// "global fees and min fees have partial overlapping denom, one min fee amount > global fee amount, combined fee = overlapping highest": { -// cGlobal: coinsNonEmpty, -// c: coinsNewOldDenomHigh, -// combined: sdk.Coins{coin1High, coin2}, -// }, -// "global fees have zero fees, min fees have overlapping non-zero fees, combined fees = overlapping highest": { -// cGlobal: coinsCointainZero, -// c: coinsNonEmpty, -// combined: sdk.Coins{coin1, coin2}, -// }, -// "global fees have zero fees, min fees have overlapping zero fees": { -// cGlobal: coinsCointainZero, -// c: coinsCointainZero, -// combined: coinsCointainZero, -// }, -// "global fees have zero fees, min fees have non-overlapping zero fees": { -// cGlobal: coinsCointainZero, -// c: coinsCointainZeroNewDenom, -// combined: coinsCointainZero, -// }, -// "global fees are all zero fees, min fees have overlapping zero fees": { -// cGlobal: coinsAllZero, -// c: coinsAllZero, -// combined: coinsAllZero, -// }, -// "global fees are all zero fees, min fees have overlapping non-zero fees, combined fee = overlapping highest": { -// cGlobal: coinsAllZero, -// c: coinsCointainZeroNewDenom, -// combined: sdk.Coins{coin1, zeroCoin2}, -// }, -// "global fees are all zero fees, fees have one overlapping non-zero fee": { -// cGlobal: coinsAllZero, -// c: coinsCointainZero, -// combined: coinsCointainZero, -// }, -// } -// -// for name, test := range tests { -// t.Run(name, func(t *testing.T) { -// allFees, err := CombinedFeeRequirement(test.cGlobal, test.c) -// if len(test.cGlobal) == 0 { -// require.Error(t, err) -// } else { -// require.NoError(t, err) -// } -// require.Equal(t, test.combined, allFees) -// }) -// } -//} -// -// func TestSplitCoinsByDenoms(t *testing.T) { -// zeroGlobalFeesDenom0 := map[string]struct{}{} -// zeroGlobalFeesDenom1 := map[string]struct{}{ -// "uatom": {}, -// "photon": {}, -// } -// zeroGlobalFeesDenom2 := map[string]struct{}{ -// "uatom": {}, -// } -// zeroGlobalFeesDenom3 := map[string]struct{}{ -// "stake": {}, -// } -// -// photon := sdk.NewCoin("photon", sdk.OneInt()) -// uatom := sdk.NewCoin("uatom", sdk.OneInt()) -// feeCoins := sdk.NewCoins(photon, uatom) -// -// tests := map[string]struct { -// feeCoins sdk.Coins -// zeroGlobalFeesDenom map[string]struct{} -// expectedNonZeroCoins sdk.Coins -// expectedZeroCoins sdk.Coins -// }{ -// "no zero coins in global fees": { -// feeCoins: feeCoins, -// zeroGlobalFeesDenom: zeroGlobalFeesDenom0, -// expectedNonZeroCoins: feeCoins, -// expectedZeroCoins: sdk.Coins{}, -// }, -// "no split of fee coins": { -// feeCoins: feeCoins, -// zeroGlobalFeesDenom: zeroGlobalFeesDenom3, -// expectedNonZeroCoins: feeCoins, -// expectedZeroCoins: sdk.Coins{}, -// }, -// "split the fee coins": { -// feeCoins: feeCoins, -// zeroGlobalFeesDenom: zeroGlobalFeesDenom2, -// expectedNonZeroCoins: sdk.NewCoins(photon), -// expectedZeroCoins: sdk.NewCoins(uatom), -// }, -// "remove all of the fee coins": { -// feeCoins: feeCoins, -// zeroGlobalFeesDenom: zeroGlobalFeesDenom1, -// expectedNonZeroCoins: sdk.Coins{}, -// expectedZeroCoins: feeCoins, -// }, -// "fee coins are empty": { -// feeCoins: sdk.Coins{}, -// zeroGlobalFeesDenom: zeroGlobalFeesDenom1, -// expectedNonZeroCoins: sdk.Coins{}, -// expectedZeroCoins: sdk.Coins{}, -// }, -// } -// -// for name, test := range tests { -// t.Run(name, func(t *testing.T) { -// feeCoinsNoZeroDenoms, feeCoinsZeroDenoms := splitCoinsByDenoms(test.feeCoins, test.zeroGlobalFeesDenom) -// require.Equal(t, test.expectedNonZeroCoins, feeCoinsNoZeroDenoms) -// require.Equal(t, test.expectedZeroCoins, feeCoinsZeroDenoms) -// }) -// } -//} -// -// func TestSplitGlobalFees(t *testing.T) { -// photon0 := sdk.NewCoin("photon", sdk.ZeroInt()) -// uatom0 := sdk.NewCoin("uatom", sdk.ZeroInt()) -// photon1 := sdk.NewCoin("photon", sdk.OneInt()) -// uatom1 := sdk.NewCoin("uatom", sdk.OneInt()) -// -// globalFeesEmpty := sdk.Coins{} -// globalFees := sdk.Coins{photon1, uatom1}.Sort() -// globalFeesZeroCoins := sdk.Coins{photon0, uatom0}.Sort() -// globalFeesMix := sdk.Coins{photon0, uatom1}.Sort() -// -// tests := map[string]struct { -// globalfees sdk.Coins -// zeroGlobalFeesDenom map[string]struct{} -// globalfeesNonZero sdk.Coins -// }{ -// "empty global fees": { -// globalfees: globalFeesEmpty, -// zeroGlobalFeesDenom: map[string]struct{}{}, -// globalfeesNonZero: sdk.Coins{}, -// }, -// "nonzero coins global fees": { -// globalfees: globalFees, -// zeroGlobalFeesDenom: map[string]struct{}{}, -// globalfeesNonZero: globalFees, -// }, -// "zero coins global fees": { -// globalfees: globalFeesZeroCoins, -// zeroGlobalFeesDenom: map[string]struct{}{ -// "photon": {}, -// "uatom": {}, -// }, -// globalfeesNonZero: sdk.Coins{}, -// }, -// "mix zero, nonzero coins global fees": { -// globalfees: globalFeesMix, -// zeroGlobalFeesDenom: map[string]struct{}{ -// "photon": {}, -// }, -// globalfeesNonZero: sdk.NewCoins(uatom1), -// }, -// } -// -// for name, test := range tests { -// t.Run(name, func(t *testing.T) { -// nonZeroCoins, zeroCoinsMap := getNonZeroFees(test.globalfees) -// require.True(t, nonZeroCoins.IsEqual(test.globalfeesNonZero)) -// require.True(t, equalMap(zeroCoinsMap, test.zeroGlobalFeesDenom)) -// }) -// } -//} -// -// func equalMap(a, b map[string]struct{}) bool { -// if len(a) != len(b) { -// return false -// } -// if len(a) == 0 && len(b) == 0 { -// return true -// } -// if len(a) == 0 { -// return false -// } -// -// for k := range a { -// if _, ok := b[k]; !ok { -// return false -// } -// } -// -// return true -//} +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestContainZeroCoins(t *testing.T) { + zeroCoin1 := sdk.NewCoin("photon", sdk.ZeroInt()) + zeroCoin2 := sdk.NewCoin("stake", sdk.ZeroInt()) + coin1 := sdk.NewCoin("photon", sdk.NewInt(1)) + coin2 := sdk.NewCoin("stake", sdk.NewInt(2)) + coin3 := sdk.NewCoin("quark", sdk.NewInt(3)) + // coins must be valid !!! + coinsEmpty := sdk.Coins{} + coinsNonEmpty := sdk.Coins{coin1, coin2} + coinsCointainZero := sdk.Coins{coin1, zeroCoin2} + coinsCointainTwoZero := sdk.Coins{zeroCoin1, zeroCoin2, coin3} + coinsAllZero := sdk.Coins{zeroCoin1, zeroCoin2} + + tests := []struct { + c sdk.Coins + ok bool + }{ + { + coinsEmpty, + true, + }, + { + coinsNonEmpty, + false, + }, + { + coinsCointainZero, + true, + }, + { + coinsCointainTwoZero, + true, + }, + { + coinsAllZero, + true, + }, + } + + for _, test := range tests { + ok := ContainZeroCoins(test.c) + require.Equal(t, test.ok, ok) + } +} + +// Note that in a real Gaia deployment all zero coins can be removed from minGasPrice. +// This sanitizing happens when the minGasPrice is set into the context. +// (see baseapp.SetMinGasPrices in gaia/cmd/root.go line 221) +func TestCombinedFeeRequirement(t *testing.T) { + zeroCoin1 := sdk.NewCoin("photon", sdk.ZeroInt()) + zeroCoin2 := sdk.NewCoin("stake", sdk.ZeroInt()) + zeroCoin3 := sdk.NewCoin("quark", sdk.ZeroInt()) + coin1 := sdk.NewCoin("photon", sdk.NewInt(1)) + coin2 := sdk.NewCoin("stake", sdk.NewInt(2)) + coin1High := sdk.NewCoin("photon", sdk.NewInt(10)) + coin2High := sdk.NewCoin("stake", sdk.NewInt(20)) + coinNewDenom1 := sdk.NewCoin("Newphoton", sdk.NewInt(1)) + coinNewDenom2 := sdk.NewCoin("Newstake", sdk.NewInt(1)) + // coins must be valid !!! and sorted!!! + coinsEmpty := sdk.Coins{} + coinsNonEmpty := sdk.Coins{coin1, coin2}.Sort() + coinsNonEmptyHigh := sdk.Coins{coin1High, coin2High}.Sort() + coinsNonEmptyOneHigh := sdk.Coins{coin1High, coin2}.Sort() + coinsNewDenom := sdk.Coins{coinNewDenom1, coinNewDenom2}.Sort() + coinsNewOldDenom := sdk.Coins{coin1, coinNewDenom1}.Sort() + coinsNewOldDenomHigh := sdk.Coins{coin1High, coinNewDenom1}.Sort() + coinsCointainZero := sdk.Coins{coin1, zeroCoin2}.Sort() + coinsCointainZeroNewDenom := sdk.Coins{coin1, zeroCoin3}.Sort() + coinsAllZero := sdk.Coins{zeroCoin1, zeroCoin2}.Sort() + tests := map[string]struct { + cGlobal sdk.Coins + c sdk.Coins + combined sdk.Coins + }{ + "global fee invalid, return combined fee empty and non-nil error": { + cGlobal: coinsEmpty, + c: coinsEmpty, + combined: coinsEmpty, + }, + "global fee nonempty, min fee empty, combined fee = global fee": { + cGlobal: coinsNonEmpty, + c: coinsNonEmpty, + combined: coinsNonEmpty, + }, + "global fee and min fee have overlapping denom, min fees amounts are all higher": { + cGlobal: coinsNonEmpty, + c: coinsNonEmptyHigh, + combined: coinsNonEmptyHigh, + }, + "global fee and min fee have overlapping denom, one of min fees amounts is higher": { + cGlobal: coinsNonEmpty, + c: coinsNonEmptyOneHigh, + combined: coinsNonEmptyOneHigh, + }, + "global fee and min fee have no overlapping denom, combined fee = global fee": { + cGlobal: coinsNonEmpty, + c: coinsNewDenom, + combined: coinsNonEmpty, + }, + "global fees and min fees have partial overlapping denom, min fee amount <= global fee amount, combined fees = global fees": { + cGlobal: coinsNonEmpty, + c: coinsNewOldDenom, + combined: coinsNonEmpty, + }, + "global fees and min fees have partial overlapping denom, one min fee amount > global fee amount, combined fee = overlapping highest": { + cGlobal: coinsNonEmpty, + c: coinsNewOldDenomHigh, + combined: sdk.Coins{coin1High, coin2}, + }, + "global fees have zero fees, min fees have overlapping non-zero fees, combined fees = overlapping highest": { + cGlobal: coinsCointainZero, + c: coinsNonEmpty, + combined: sdk.Coins{coin1, coin2}, + }, + "global fees have zero fees, min fees have overlapping zero fees": { + cGlobal: coinsCointainZero, + c: coinsCointainZero, + combined: coinsCointainZero, + }, + "global fees have zero fees, min fees have non-overlapping zero fees": { + cGlobal: coinsCointainZero, + c: coinsCointainZeroNewDenom, + combined: coinsCointainZero, + }, + "global fees are all zero fees, min fees have overlapping zero fees": { + cGlobal: coinsAllZero, + c: coinsAllZero, + combined: coinsAllZero, + }, + "global fees are all zero fees, min fees have overlapping non-zero fees, combined fee = overlapping highest": { + cGlobal: coinsAllZero, + c: coinsCointainZeroNewDenom, + combined: sdk.Coins{coin1, zeroCoin2}, + }, + "global fees are all zero fees, fees have one overlapping non-zero fee": { + cGlobal: coinsAllZero, + c: coinsCointainZero, + combined: coinsCointainZero, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + allFees, err := CombinedFeeRequirement(test.cGlobal, test.c) + if len(test.cGlobal) == 0 { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Equal(t, test.combined, allFees) + }) + } +} + +func TestSplitCoinsByDenoms(t *testing.T) { + zeroGlobalFeesDenom0 := map[string]struct{}{} + zeroGlobalFeesDenom1 := map[string]struct{}{ + "uatom": {}, + "photon": {}, + } + zeroGlobalFeesDenom2 := map[string]struct{}{ + "uatom": {}, + } + zeroGlobalFeesDenom3 := map[string]struct{}{ + "stake": {}, + } + + photon := sdk.NewCoin("photon", sdk.OneInt()) + uatom := sdk.NewCoin("uatom", sdk.OneInt()) + feeCoins := sdk.NewCoins(photon, uatom) + + tests := map[string]struct { + feeCoins sdk.Coins + zeroGlobalFeesDenom map[string]struct{} + expectedNonZeroCoins sdk.Coins + expectedZeroCoins sdk.Coins + }{ + "no zero coins in global fees": { + feeCoins: feeCoins, + zeroGlobalFeesDenom: zeroGlobalFeesDenom0, + expectedNonZeroCoins: feeCoins, + expectedZeroCoins: sdk.Coins{}, + }, + "no split of fee coins": { + feeCoins: feeCoins, + zeroGlobalFeesDenom: zeroGlobalFeesDenom3, + expectedNonZeroCoins: feeCoins, + expectedZeroCoins: sdk.Coins{}, + }, + "split the fee coins": { + feeCoins: feeCoins, + zeroGlobalFeesDenom: zeroGlobalFeesDenom2, + expectedNonZeroCoins: sdk.NewCoins(photon), + expectedZeroCoins: sdk.NewCoins(uatom), + }, + "remove all of the fee coins": { + feeCoins: feeCoins, + zeroGlobalFeesDenom: zeroGlobalFeesDenom1, + expectedNonZeroCoins: sdk.Coins{}, + expectedZeroCoins: feeCoins, + }, + "fee coins are empty": { + feeCoins: sdk.Coins{}, + zeroGlobalFeesDenom: zeroGlobalFeesDenom1, + expectedNonZeroCoins: sdk.Coins{}, + expectedZeroCoins: sdk.Coins{}, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + feeCoinsNoZeroDenoms, feeCoinsZeroDenoms := splitCoinsByDenoms(test.feeCoins, test.zeroGlobalFeesDenom) + require.Equal(t, test.expectedNonZeroCoins, feeCoinsNoZeroDenoms) + require.Equal(t, test.expectedZeroCoins, feeCoinsZeroDenoms) + }) + } +} + +func TestSplitGlobalFees(t *testing.T) { + photon0 := sdk.NewCoin("photon", sdk.ZeroInt()) + uatom0 := sdk.NewCoin("uatom", sdk.ZeroInt()) + photon1 := sdk.NewCoin("photon", sdk.OneInt()) + uatom1 := sdk.NewCoin("uatom", sdk.OneInt()) + + globalFeesEmpty := sdk.Coins{} + globalFees := sdk.Coins{photon1, uatom1}.Sort() + globalFeesZeroCoins := sdk.Coins{photon0, uatom0}.Sort() + globalFeesMix := sdk.Coins{photon0, uatom1}.Sort() + + tests := map[string]struct { + globalfees sdk.Coins + zeroGlobalFeesDenom map[string]struct{} + globalfeesNonZero sdk.Coins + }{ + "empty global fees": { + globalfees: globalFeesEmpty, + zeroGlobalFeesDenom: map[string]struct{}{}, + globalfeesNonZero: sdk.Coins{}, + }, + "nonzero coins global fees": { + globalfees: globalFees, + zeroGlobalFeesDenom: map[string]struct{}{}, + globalfeesNonZero: globalFees, + }, + "zero coins global fees": { + globalfees: globalFeesZeroCoins, + zeroGlobalFeesDenom: map[string]struct{}{ + "photon": {}, + "uatom": {}, + }, + globalfeesNonZero: sdk.Coins{}, + }, + "mix zero, nonzero coins global fees": { + globalfees: globalFeesMix, + zeroGlobalFeesDenom: map[string]struct{}{ + "photon": {}, + }, + globalfeesNonZero: sdk.NewCoins(uatom1), + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + nonZeroCoins, zeroCoinsMap := getNonZeroFees(test.globalfees) + require.True(t, nonZeroCoins.IsEqual(test.globalfeesNonZero)) + require.True(t, equalMap(zeroCoinsMap, test.zeroGlobalFeesDenom)) + }) + } +} + +func equalMap(a, b map[string]struct{}) bool { + if len(a) != len(b) { + return false + } + if len(a) == 0 && len(b) == 0 { + return true + } + if len(a) == 0 { + return false + } + + for k := range a { + if _, ok := b[k]; !ok { + return false + } + } + + return true +} diff --git a/x/globalfee/client/cli/query.go b/x/globalfee/client/cli/query.go index ebce304ad00..b3b2056fc37 100644 --- a/x/globalfee/client/cli/query.go +++ b/x/globalfee/client/cli/query.go @@ -1,47 +1,47 @@ package cli -// import ( -// "github.com/cosmos/cosmos-sdk/client" -// "github.com/cosmos/cosmos-sdk/client/flags" -// "github.com/spf13/cobra" +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" -// "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) + "github.com/cosmos/gaia/v11/x/globalfee/types" +) -// func GetQueryCmd() *cobra.Command { -// queryCmd := &cobra.Command{ -// Use: types.ModuleName, -// Short: "Querying commands for the global fee module", -// DisableFlagParsing: true, -// SuggestionsMinimumDistance: 2, -// RunE: client.ValidateCmd, -// } -// queryCmd.AddCommand( -// GetCmdShowGlobalFeeParams(), -// ) -// return queryCmd -// } +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the global fee module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + queryCmd.AddCommand( + GetCmdShowGlobalFeeParams(), + ) + return queryCmd +} -// func GetCmdShowGlobalFeeParams() *cobra.Command { -// cmd := &cobra.Command{ -// Use: "params", -// Short: "Show globalfee params", -// Long: "Show globalfee requirement: minimum_gas_prices, bypass_min_fee_msg_types, max_total_bypass_minFee_msg_gas_usage", -// Args: cobra.ExactArgs(0), -// RunE: func(cmd *cobra.Command, args []string) error { -// clientCtx, err := client.GetClientQueryContext(cmd) -// if err != nil { -// return err -// } +func GetCmdShowGlobalFeeParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Show globalfee params", + Long: "Show globalfee requirement: minimum_gas_prices, bypass_min_fee_msg_types, max_total_bypass_minFee_msg_gas_usage", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } -// queryClient := types.NewQueryClient(clientCtx) -// res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) -// if err != nil { -// return err -// } -// return clientCtx.PrintProto(&res.Params) -// }, -// } -// flags.AddQueryFlagsToCmd(cmd) -// return cmd -// } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + return clientCtx.PrintProto(&res.Params) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/globalfee/keeper/migrations.go b/x/globalfee/keeper/migrations.go index 3f2e40e12d0..64f08edd3b6 100644 --- a/x/globalfee/keeper/migrations.go +++ b/x/globalfee/keeper/migrations.go @@ -1,23 +1,23 @@ package keeper -// import ( -// sdk "github.com/cosmos/cosmos-sdk/types" -// paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -// v2 "github.com/cosmos/gaia/v11/x/globalfee/migrations/v2" -// ) + v2 "github.com/cosmos/gaia/v11/x/globalfee/migrations/v2" +) -// // Migrator is a struct for handling in-place store migrations. -// type Migrator struct { -// globalfeeSubspace paramtypes.Subspace -// } +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + globalfeeSubspace paramtypes.Subspace +} -// // NewMigrator returns a new Migrator. -// func NewMigrator(globalfeeSubspace paramtypes.Subspace) Migrator { -// return Migrator{globalfeeSubspace: globalfeeSubspace} -// } +// NewMigrator returns a new Migrator. +func NewMigrator(globalfeeSubspace paramtypes.Subspace) Migrator { + return Migrator{globalfeeSubspace: globalfeeSubspace} +} -// // Migrate1to2 migrates from version 1 to 2. -// func (m Migrator) Migrate1to2(ctx sdk.Context) error { -// return v2.MigrateStore(ctx, m.globalfeeSubspace) -// } +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.MigrateStore(ctx, m.globalfeeSubspace) +} diff --git a/x/globalfee/migrations/v2/migration.go b/x/globalfee/migrations/v2/migration.go index a49cbe5b631..176ff59d6f1 100644 --- a/x/globalfee/migrations/v2/migration.go +++ b/x/globalfee/migrations/v2/migration.go @@ -1,5 +1,12 @@ package v2 +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/cosmos/gaia/v11/x/globalfee/types" +) + // MigrateStore performs in-place params migrations of // BypassMinFeeMsgTypes and MaxTotalBypassMinFeeMsgGasUsage // from app.toml to globalfee params. @@ -11,21 +18,21 @@ package v2 // "/ibc.core.channel.v1.MsgTimeout", // "/ibc.core.channel.v1.MsgTimeoutOnClose"] as default and // add MaxTotalBypassMinFeeMsgGasUsage that is set 1_000_000 as default. -// func MigrateStore(ctx sdk.Context, globalfeeSubspace paramtypes.Subspace) error { -// var oldGlobalMinGasPrices sdk.DecCoins -// globalfeeSubspace.Get(ctx, types.ParamStoreKeyMinGasPrices, &oldGlobalMinGasPrices) -// defaultParams := types.DefaultParams() -// params := types.Params{ -// MinimumGasPrices: oldGlobalMinGasPrices, -// BypassMinFeeMsgTypes: defaultParams.BypassMinFeeMsgTypes, -// MaxTotalBypassMinFeeMsgGasUsage: defaultParams.MaxTotalBypassMinFeeMsgGasUsage, -// } +func MigrateStore(ctx sdk.Context, globalfeeSubspace paramtypes.Subspace) error { + var oldGlobalMinGasPrices sdk.DecCoins + globalfeeSubspace.Get(ctx, types.ParamStoreKeyMinGasPrices, &oldGlobalMinGasPrices) + defaultParams := types.DefaultParams() + params := types.Params{ + MinimumGasPrices: oldGlobalMinGasPrices, + BypassMinFeeMsgTypes: defaultParams.BypassMinFeeMsgTypes, + MaxTotalBypassMinFeeMsgGasUsage: defaultParams.MaxTotalBypassMinFeeMsgGasUsage, + } -// if !globalfeeSubspace.HasKeyTable() { -// globalfeeSubspace = globalfeeSubspace.WithKeyTable(types.ParamKeyTable()) -// } + if !globalfeeSubspace.HasKeyTable() { + globalfeeSubspace = globalfeeSubspace.WithKeyTable(types.ParamKeyTable()) + } -// globalfeeSubspace.SetParamSet(ctx, ¶ms) + globalfeeSubspace.SetParamSet(ctx, ¶ms) -// return nil -// } + return nil +} diff --git a/x/globalfee/migrations/v2/v2_test/migration_test.go b/x/globalfee/migrations/v2/v2_test/migration_test.go index b8f257906c0..7b6e5a2425e 100644 --- a/x/globalfee/migrations/v2/v2_test/migration_test.go +++ b/x/globalfee/migrations/v2/v2_test/migration_test.go @@ -1,107 +1,108 @@ package v2_test -// import ( -// "testing" - -// "github.com/cosmos/cosmos-sdk/codec" -// codectypes "github.com/cosmos/cosmos-sdk/codec/types" -// "github.com/cosmos/cosmos-sdk/store" -// storetypes "github.com/cosmos/cosmos-sdk/store/types" -// sdk "github.com/cosmos/cosmos-sdk/types" -// paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -// v2 "github.com/cosmos/gaia/v11/x/globalfee/migrations/v2" -// globalfeetypes "github.com/cosmos/gaia/v11/x/globalfee/types" -// "github.com/stretchr/testify/require" -// "github.com/tendermint/tendermint/libs/log" -// tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -// tmdb "github.com/tendermint/tm-db" -// ) - -// func TestMigrateStore(t *testing.T) { -// db := tmdb.NewMemDB() -// stateStore := store.NewCommitMultiStore(db) - -// storeKey := sdk.NewKVStoreKey(paramtypes.StoreKey) -// memStoreKey := storetypes.NewMemoryStoreKey("mem_key") - -// stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) -// stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) -// require.NoError(t, stateStore.LoadLatestVersion()) - -// registry := codectypes.NewInterfaceRegistry() -// cdc := codec.NewProtoCodec(registry) -// ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - -// require.NoError(t, stateStore.LoadLatestVersion()) - -// // Create new empty subspace -// newSubspace := paramtypes.NewSubspace(cdc, -// codec.NewLegacyAmino(), -// storeKey, -// memStoreKey, -// paramtypes.ModuleName, -// ) - -// // register the subspace with the v11 paramKeyTable -// newSubspace = newSubspace.WithKeyTable(globalfeetypes.ParamKeyTable()) - -// // check MinGasPrices isn't set -// _, ok := getMinGasPrice(newSubspace, ctx) -// require.Equal(t, ok, false) - -// // set a minGasPrice different that default value -// minGasPrices := sdk.NewDecCoins(sdk.NewDecCoin("uatom", sdk.OneInt())) -// newSubspace.Set(ctx, globalfeetypes.ParamStoreKeyMinGasPrices, minGasPrices) -// require.False(t, minGasPrices.IsEqual(globalfeetypes.DefaultMinGasPrices)) - -// // check that the new parameters aren't set -// _, ok = getBypassMsgTypes(newSubspace, ctx) -// require.Equal(t, ok, false) -// _, ok = getMaxTotalBypassMinFeeMsgGasUsage(newSubspace, ctx) -// require.Equal(t, ok, false) - -// // run global fee migration -// err := v2.MigrateStore(ctx, newSubspace) -// require.NoError(t, err) - -// newMinGasPrices, _ := getMinGasPrice(newSubspace, ctx) -// bypassMsgTypes, _ := getBypassMsgTypes(newSubspace, ctx) -// maxGas, _ := getMaxTotalBypassMinFeeMsgGasUsage(newSubspace, ctx) - -// require.Equal(t, bypassMsgTypes, globalfeetypes.DefaultBypassMinFeeMsgTypes) -// require.Equal(t, maxGas, globalfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage) -// require.Equal(t, minGasPrices, newMinGasPrices) -// } - -// func getBypassMsgTypes(globalfeeSubspace paramtypes.Subspace, ctx sdk.Context) ([]string, bool) { -// bypassMsgs := []string{} -// if globalfeeSubspace.Has(ctx, globalfeetypes.ParamStoreKeyBypassMinFeeMsgTypes) { -// globalfeeSubspace.Get(ctx, globalfeetypes.ParamStoreKeyBypassMinFeeMsgTypes, &bypassMsgs) -// } else { -// return bypassMsgs, false -// } - -// return bypassMsgs, true -// } - -// func getMaxTotalBypassMinFeeMsgGasUsage(globalfeeSubspace paramtypes.Subspace, ctx sdk.Context) (uint64, bool) { -// var maxTotalBypassMinFeeMsgGasUsage uint64 -// if globalfeeSubspace.Has(ctx, globalfeetypes.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage) { -// globalfeeSubspace.Get(ctx, globalfeetypes.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &maxTotalBypassMinFeeMsgGasUsage) -// } else { -// return maxTotalBypassMinFeeMsgGasUsage, false -// } - -// return maxTotalBypassMinFeeMsgGasUsage, true -// } - -// func getMinGasPrice(globalfeeSubspace paramtypes.Subspace, ctx sdk.Context) (sdk.DecCoins, bool) { -// var globalMinGasPrices sdk.DecCoins -// if globalfeeSubspace.Has(ctx, globalfeetypes.ParamStoreKeyMinGasPrices) { -// globalfeeSubspace.Get(ctx, globalfeetypes.ParamStoreKeyMinGasPrices, &globalMinGasPrices) -// } else { -// return globalMinGasPrices, false -// } - -// return globalMinGasPrices, true -// } +import ( + "testing" + + cmdb "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/stretchr/testify/require" + + v2 "github.com/cosmos/gaia/v11/x/globalfee/migrations/v2" + globalfeetypes "github.com/cosmos/gaia/v11/x/globalfee/types" +) + +func TestMigrateStore(t *testing.T) { + db := cmdb.NewMemDB() + stateStore := store.NewCommitMultiStore(db) + + storeKey := sdk.NewKVStoreKey(paramtypes.StoreKey) + memStoreKey := storetypes.NewMemoryStoreKey("mem_key") + + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(memStoreKey, storetypes.StoreTypeMemory, nil) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) + + require.NoError(t, stateStore.LoadLatestVersion()) + + // Create new empty subspace + newSubspace := paramtypes.NewSubspace(cdc, + codec.NewLegacyAmino(), + storeKey, + memStoreKey, + paramtypes.ModuleName, + ) + + // register the subspace with the v11 paramKeyTable + newSubspace = newSubspace.WithKeyTable(globalfeetypes.ParamKeyTable()) + + // check MinGasPrices isn't set + _, ok := getMinGasPrice(newSubspace, ctx) + require.Equal(t, ok, false) + + // set a minGasPrice different that default value + minGasPrices := sdk.NewDecCoins(sdk.NewDecCoin("uatom", sdk.OneInt())) + newSubspace.Set(ctx, globalfeetypes.ParamStoreKeyMinGasPrices, minGasPrices) + require.False(t, minGasPrices.IsEqual(globalfeetypes.DefaultMinGasPrices)) + + // check that the new parameters aren't set + _, ok = getBypassMsgTypes(newSubspace, ctx) + require.Equal(t, ok, false) + _, ok = getMaxTotalBypassMinFeeMsgGasUsage(newSubspace, ctx) + require.Equal(t, ok, false) + + // run global fee migration + err := v2.MigrateStore(ctx, newSubspace) + require.NoError(t, err) + + newMinGasPrices, _ := getMinGasPrice(newSubspace, ctx) + bypassMsgTypes, _ := getBypassMsgTypes(newSubspace, ctx) + maxGas, _ := getMaxTotalBypassMinFeeMsgGasUsage(newSubspace, ctx) + + require.Equal(t, bypassMsgTypes, globalfeetypes.DefaultBypassMinFeeMsgTypes) + require.Equal(t, maxGas, globalfeetypes.DefaultmaxTotalBypassMinFeeMsgGasUsage) + require.Equal(t, minGasPrices, newMinGasPrices) +} + +func getBypassMsgTypes(globalfeeSubspace paramtypes.Subspace, ctx sdk.Context) ([]string, bool) { + bypassMsgs := []string{} + if globalfeeSubspace.Has(ctx, globalfeetypes.ParamStoreKeyBypassMinFeeMsgTypes) { + globalfeeSubspace.Get(ctx, globalfeetypes.ParamStoreKeyBypassMinFeeMsgTypes, &bypassMsgs) + } else { + return bypassMsgs, false + } + + return bypassMsgs, true +} + +func getMaxTotalBypassMinFeeMsgGasUsage(globalfeeSubspace paramtypes.Subspace, ctx sdk.Context) (uint64, bool) { + var maxTotalBypassMinFeeMsgGasUsage uint64 + if globalfeeSubspace.Has(ctx, globalfeetypes.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage) { + globalfeeSubspace.Get(ctx, globalfeetypes.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &maxTotalBypassMinFeeMsgGasUsage) + } else { + return maxTotalBypassMinFeeMsgGasUsage, false + } + + return maxTotalBypassMinFeeMsgGasUsage, true +} + +func getMinGasPrice(globalfeeSubspace paramtypes.Subspace, ctx sdk.Context) (sdk.DecCoins, bool) { + var globalMinGasPrices sdk.DecCoins + if globalfeeSubspace.Has(ctx, globalfeetypes.ParamStoreKeyMinGasPrices) { + globalfeeSubspace.Get(ctx, globalfeetypes.ParamStoreKeyMinGasPrices, &globalMinGasPrices) + } else { + return globalMinGasPrices, false + } + + return globalMinGasPrices, true +} diff --git a/x/globalfee/module.go b/x/globalfee/module.go index e1e367455f2..d6add4249f1 100644 --- a/x/globalfee/module.go +++ b/x/globalfee/module.go @@ -1,146 +1,134 @@ package globalfee -// import ( -// "context" -// "encoding/json" -// "fmt" - -// errorsmod "cosmossdk.io/errors" -// "github.com/cosmos/cosmos-sdk/client" -// "github.com/cosmos/cosmos-sdk/codec" -// codectypes "github.com/cosmos/cosmos-sdk/codec/types" -// sdk "github.com/cosmos/cosmos-sdk/types" -// "github.com/cosmos/cosmos-sdk/types/module" -// paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" -// "github.com/gorilla/mux" -// "github.com/grpc-ecosystem/grpc-gateway/runtime" -// "github.com/spf13/cobra" -// abci "github.com/tendermint/tendermint/abci/types" - -// "github.com/cosmos/gaia/v11/x/globalfee/client/cli" -// "github.com/cosmos/gaia/v11/x/globalfee/keeper" -// "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) - -// var ( -// _ module.AppModuleBasic = AppModuleBasic{} -// _ module.AppModuleGenesis = AppModule{} -// _ module.AppModule = AppModule{} -// ) - -// // AppModuleBasic defines the basic application module used by the wasm module. -// type AppModuleBasic struct{} - -// func (a AppModuleBasic) Name() string { -// return types.ModuleName -// } - -// func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { -// return cdc.MustMarshalJSON(&types.GenesisState{ -// Params: types.DefaultParams(), -// }) -// } - -// func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { -// var data types.GenesisState -// err := marshaler.UnmarshalJSON(message, &data) -// if err != nil { -// return err -// } -// if err := data.Params.ValidateBasic(); err != nil { -// return errorsmod.Wrap(err, "params") -// } -// return nil -// } - -// func (a AppModuleBasic) RegisterInterfaces(_ codectypes.InterfaceRegistry) { -// } - -// func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { -// } - -// func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { -// err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) -// if err != nil { -// // same behavior as in cosmos-sdk -// panic(err) -// } -// } - -// func (a AppModuleBasic) GetTxCmd() *cobra.Command { -// return nil -// } - -// func (a AppModuleBasic) GetQueryCmd() *cobra.Command { -// return cli.GetQueryCmd() -// } - -// func (a AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) { -// } - -// type AppModule struct { -// AppModuleBasic -// paramSpace paramstypes.Subspace -// } - -// // NewAppModule constructor -// func NewAppModule(paramSpace paramstypes.Subspace) *AppModule { -// if !paramSpace.HasKeyTable() { -// paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) -// } - -// return &AppModule{paramSpace: paramSpace} -// } - -// func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { -// var genesisState types.GenesisState -// marshaler.MustUnmarshalJSON(message, &genesisState) - -// a.paramSpace.SetParamSet(ctx, &genesisState.Params) -// return nil -// } - -// func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { -// var genState types.GenesisState -// a.paramSpace.GetParamSet(ctx, &genState.Params) -// return marshaler.MustMarshalJSON(&genState) -// } - -// func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { -// } - -// func (a AppModule) Route() sdk.Route { -// return sdk.Route{} -// } - -// func (a AppModule) QuerierRoute() string { -// return types.QuerierRoute -// } - -// func (a AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { -// return nil -// } - -// func (a AppModule) RegisterServices(cfg module.Configurator) { -// types.RegisterQueryServer(cfg.QueryServer(), NewGrpcQuerier(a.paramSpace)) - -// m := keeper.NewMigrator(a.paramSpace) -// if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { -// panic(fmt.Sprintf("failed to migrate x/globalfee from version 1 to 2: %v", err)) -// } -// } - -// func (a AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { -// } - -// func (a AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { -// return nil -// } - -// // ConsensusVersion is a sequence number for state-breaking change of the -// // module. It should be incremented on each consensus-breaking change -// // introduced by the module. To avoid wrong/empty versions, the initial version -// // should be set to 1. -// func (a AppModule) ConsensusVersion() uint64 { -// return 2 -// } +import ( + "context" + "encoding/json" + "fmt" + + errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "github.com/cosmos/gaia/v11/x/globalfee/client/cli" + "github.com/cosmos/gaia/v11/x/globalfee/keeper" + "github.com/cosmos/gaia/v11/x/globalfee/types" +) + +var ( + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleGenesis = AppModule{} + _ module.AppModule = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the wasm module. +type AppModuleBasic struct{} + +func (a AppModuleBasic) Name() string { + return types.ModuleName +} + +func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(&types.GenesisState{ + Params: types.DefaultParams(), + }) +} + +func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { + var data types.GenesisState + err := marshaler.UnmarshalJSON(message, &data) + if err != nil { + return err + } + if err := data.Params.ValidateBasic(); err != nil { + return errorsmod.Wrap(err, "params") + } + return nil +} + +func (a AppModuleBasic) RegisterInterfaces(_ codectypes.InterfaceRegistry) { +} + +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { +} + +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + // same behavior as in cosmos-sdk + panic(err) + } +} + +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return nil +} + +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +func (a AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) { +} + +type AppModule struct { + AppModuleBasic + paramSpace paramstypes.Subspace +} + +// NewAppModule constructor +func NewAppModule(paramSpace paramstypes.Subspace) *AppModule { + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + return &AppModule{paramSpace: paramSpace} +} + +func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + marshaler.MustUnmarshalJSON(message, &genesisState) + + a.paramSpace.SetParamSet(ctx, &genesisState.Params) + return nil +} + +func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { + var genState types.GenesisState + a.paramSpace.GetParamSet(ctx, &genState.Params) + return marshaler.MustMarshalJSON(&genState) +} + +func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { +} + +func (a AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), NewGrpcQuerier(a.paramSpace)) + + m := keeper.NewMigrator(a.paramSpace) + if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + panic(fmt.Sprintf("failed to migrate x/globalfee from version 1 to 2: %v", err)) + } +} + +func (a AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { +} + +func (a AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return nil +} + +// ConsensusVersion is a sequence number for state-breaking change of the +// module. It should be incremented on each consensus-breaking change +// introduced by the module. To avoid wrong/empty versions, the initial version +// should be set to 1. +func (a AppModule) ConsensusVersion() uint64 { + return 2 +} diff --git a/x/globalfee/querier.go b/x/globalfee/querier.go index 93d30999d74..4ddd5ac28f7 100644 --- a/x/globalfee/querier.go +++ b/x/globalfee/querier.go @@ -1,52 +1,52 @@ package globalfee -// import ( -// "context" - -// sdk "github.com/cosmos/cosmos-sdk/types" - -// "github.com/cosmos/gaia/v11/x/globalfee/types" -// ) - -// var _ types.QueryServer = &GrpcQuerier{} - -// // ParamSource is a read only subset of paramtypes.Subspace -// type ParamSource interface { -// Get(ctx sdk.Context, key []byte, ptr interface{}) -// Has(ctx sdk.Context, key []byte) bool -// } - -// type GrpcQuerier struct { -// paramSource ParamSource -// } - -// func NewGrpcQuerier(paramSource ParamSource) GrpcQuerier { -// return GrpcQuerier{paramSource: paramSource} -// } - -// // MinimumGasPrices return minimum gas prices -// func (g GrpcQuerier) Params(stdCtx context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { -// var minGasPrices sdk.DecCoins -// var bypassMinFeeMsgTypes []string -// var maxTotalBypassMinFeeMsgGasUsage uint64 -// ctx := sdk.UnwrapSDKContext(stdCtx) - -// // todo: if return err if not exist? -// if g.paramSource.Has(ctx, types.ParamStoreKeyMinGasPrices) { -// g.paramSource.Get(ctx, types.ParamStoreKeyMinGasPrices, &minGasPrices) -// } -// if g.paramSource.Has(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes) { -// g.paramSource.Get(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes, &bypassMinFeeMsgTypes) -// } -// if g.paramSource.Has(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage) { -// g.paramSource.Get(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &maxTotalBypassMinFeeMsgGasUsage) -// } - -// return &types.QueryParamsResponse{ -// Params: types.Params{ -// MinimumGasPrices: minGasPrices, -// BypassMinFeeMsgTypes: bypassMinFeeMsgTypes, -// MaxTotalBypassMinFeeMsgGasUsage: maxTotalBypassMinFeeMsgGasUsage, -// }, -// }, nil -// } +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v11/x/globalfee/types" +) + +var _ types.QueryServer = &GrpcQuerier{} + +// ParamSource is a read only subset of paramtypes.Subspace +type ParamSource interface { + Get(ctx sdk.Context, key []byte, ptr interface{}) + Has(ctx sdk.Context, key []byte) bool +} + +type GrpcQuerier struct { + paramSource ParamSource +} + +func NewGrpcQuerier(paramSource ParamSource) GrpcQuerier { + return GrpcQuerier{paramSource: paramSource} +} + +// MinimumGasPrices return minimum gas prices +func (g GrpcQuerier) Params(stdCtx context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + var minGasPrices sdk.DecCoins + var bypassMinFeeMsgTypes []string + var maxTotalBypassMinFeeMsgGasUsage uint64 + ctx := sdk.UnwrapSDKContext(stdCtx) + + // todo: if return err if not exist? + if g.paramSource.Has(ctx, types.ParamStoreKeyMinGasPrices) { + g.paramSource.Get(ctx, types.ParamStoreKeyMinGasPrices, &minGasPrices) + } + if g.paramSource.Has(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes) { + g.paramSource.Get(ctx, types.ParamStoreKeyBypassMinFeeMsgTypes, &bypassMinFeeMsgTypes) + } + if g.paramSource.Has(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage) { + g.paramSource.Get(ctx, types.ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &maxTotalBypassMinFeeMsgGasUsage) + } + + return &types.QueryParamsResponse{ + Params: types.Params{ + MinimumGasPrices: minGasPrices, + BypassMinFeeMsgTypes: bypassMinFeeMsgTypes, + MaxTotalBypassMinFeeMsgGasUsage: maxTotalBypassMinFeeMsgGasUsage, + }, + }, nil +} diff --git a/x/globalfee/types/genesis.go b/x/globalfee/types/genesis.go index 5d045dd9b54..253df889c6a 100644 --- a/x/globalfee/types/genesis.go +++ b/x/globalfee/types/genesis.go @@ -1,40 +1,40 @@ package types -// import ( -// "encoding/json" - -// errorsmod "cosmossdk.io/errors" -// "github.com/cosmos/cosmos-sdk/codec" -// ) - -// // NewGenesisState - Create a new genesis state -// func NewGenesisState(params Params) *GenesisState { -// return &GenesisState{ -// Params: params, -// } -// } - -// // DefaultGenesisState - Return a default genesis state -// func DefaultGenesisState() *GenesisState { -// return NewGenesisState(DefaultParams()) -// } - -// // GetGenesisStateFromAppState returns x/auth GenesisState given raw application -// // genesis state. -// func GetGenesisStateFromAppState(cdc codec.Codec, appState map[string]json.RawMessage) *GenesisState { -// var genesisState GenesisState - -// if appState[ModuleName] != nil { -// cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) -// } - -// return &genesisState -// } - -// func ValidateGenesis(data GenesisState) error { -// if err := data.Params.ValidateBasic(); err != nil { -// return errorsmod.Wrap(err, "globalfee params") -// } - -// return nil -// } +import ( + "encoding/json" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/codec" +) + +// NewGenesisState - Create a new genesis state +func NewGenesisState(params Params) *GenesisState { + return &GenesisState{ + Params: params, + } +} + +// DefaultGenesisState - Return a default genesis state +func DefaultGenesisState() *GenesisState { + return NewGenesisState(DefaultParams()) +} + +// GetGenesisStateFromAppState returns x/auth GenesisState given raw application +// genesis state. +func GetGenesisStateFromAppState(cdc codec.Codec, appState map[string]json.RawMessage) *GenesisState { + var genesisState GenesisState + + if appState[ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) + } + + return &genesisState +} + +func ValidateGenesis(data GenesisState) error { + if err := data.Params.ValidateBasic(); err != nil { + return errorsmod.Wrap(err, "globalfee params") + } + + return nil +} diff --git a/x/globalfee/types/genesis.pb.go b/x/globalfee/types/genesis.pb.go index f42a1699b2e..a5f48d07679 100644 --- a/x/globalfee/types/genesis.pb.go +++ b/x/globalfee/types/genesis.pb.go @@ -1,12 +1,17 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: gaia/globalfee/v1/genesis.proto +// source: gaia/globalfee/v1beta1/genesis.proto package types import ( fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" + io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -20,14 +25,598 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -func init() { proto.RegisterFile("gaia/globalfee/v1/genesis.proto", fileDescriptor_adcbe28f22ae5b0a) } +// GenesisState - initial state of module +type GenesisState struct { + // Params of this module + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_015b3e8b7a7c65c5, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// Params defines the set of module parameters. +type Params struct { + // minimum_gas_prices stores the minimum gas price(s) for all TX on the chain. + // When multiple coins are defined then they are accepted alternatively. + // The list must be sorted by denoms asc. No duplicate denoms or zero amount + // values allowed. For more information see + // https://docs.cosmos.network/main/modules/auth#concepts + MinimumGasPrices github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=minimum_gas_prices,json=minimumGasPrices,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"minimum_gas_prices,omitempty" yaml:"minimum_gas_prices"` + // bypass_min_fee_msg_types defines a list of message type urls + // that are free of fee charge. + BypassMinFeeMsgTypes []string `protobuf:"bytes,2,rep,name=bypass_min_fee_msg_types,json=bypassMinFeeMsgTypes,proto3" json:"bypass_min_fee_msg_types,omitempty" yaml:"bypass_min_fee_msg_types"` + // max_total_bypass_min_fee_msg_gas_usage defines the total maximum gas usage + // allowed for a transaction containing only messages of types in bypass_min_fee_msg_types + // to bypass fee charge. + MaxTotalBypassMinFeeMsgGasUsage uint64 `protobuf:"varint,3,opt,name=max_total_bypass_min_fee_msg_gas_usage,json=maxTotalBypassMinFeeMsgGasUsage,proto3" json:"max_total_bypass_min_fee_msg_gas_usage,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_015b3e8b7a7c65c5, []int{1} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetMinimumGasPrices() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.MinimumGasPrices + } + return nil +} + +func (m *Params) GetBypassMinFeeMsgTypes() []string { + if m != nil { + return m.BypassMinFeeMsgTypes + } + return nil +} + +func (m *Params) GetMaxTotalBypassMinFeeMsgGasUsage() uint64 { + if m != nil { + return m.MaxTotalBypassMinFeeMsgGasUsage + } + return 0 +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "gaia.globalfee.v1beta1.GenesisState") + proto.RegisterType((*Params)(nil), "gaia.globalfee.v1beta1.Params") +} -var fileDescriptor_adcbe28f22ae5b0a = []byte{ - // 90 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0x4f, 0xcc, 0x4c, - 0xd4, 0x4f, 0xcf, 0xc9, 0x4f, 0x4a, 0xcc, 0x49, 0x4b, 0x4d, 0xd5, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, - 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x77, 0x92, 0x38, 0xf1, 0x48, - 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, - 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x24, 0x36, 0xb0, 0x02, 0x63, 0x40, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xd4, 0x1e, 0x8a, 0x2e, 0x43, 0x00, 0x00, 0x00, +func init() { + proto.RegisterFile("gaia/globalfee/v1beta1/genesis.proto", fileDescriptor_015b3e8b7a7c65c5) } + +var fileDescriptor_015b3e8b7a7c65c5 = []byte{ + // 428 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x4d, 0x6e, 0xd3, 0x40, + 0x14, 0xc7, 0x33, 0x04, 0x45, 0xc2, 0x65, 0x51, 0x59, 0x15, 0x32, 0x55, 0x35, 0x8e, 0x2c, 0x84, + 0x2c, 0x01, 0x63, 0xb5, 0xec, 0x58, 0x1a, 0x44, 0xc4, 0xa2, 0x22, 0x0a, 0x65, 0xc3, 0x66, 0x78, + 0x36, 0xd3, 0x61, 0x44, 0xc6, 0x63, 0xe5, 0x4d, 0x50, 0xb2, 0xe4, 0x06, 0x1c, 0x80, 0x13, 0x70, + 0x06, 0x0e, 0xd0, 0x65, 0x97, 0xac, 0x0c, 0x4a, 0x76, 0x5d, 0x72, 0x02, 0x34, 0x1e, 0xd3, 0x52, + 0xa5, 0x59, 0xd9, 0xf2, 0xfb, 0xfd, 0x3f, 0xfc, 0xf4, 0x82, 0x07, 0x12, 0x14, 0x64, 0x72, 0x6a, + 0x0a, 0x98, 0x9e, 0x0a, 0x91, 0x7d, 0x3e, 0x2c, 0x84, 0x85, 0xc3, 0x4c, 0x8a, 0x4a, 0xa0, 0x42, + 0x56, 0xcf, 0x8c, 0x35, 0xe1, 0x3d, 0x47, 0xb1, 0x4b, 0x8a, 0x75, 0xd4, 0xfe, 0x9e, 0x34, 0xd2, + 0xb4, 0x48, 0xe6, 0xde, 0x3c, 0xbd, 0x4f, 0x4b, 0x83, 0xda, 0x60, 0x56, 0x00, 0x5e, 0x19, 0x96, + 0x46, 0x55, 0x7e, 0x9e, 0xbc, 0x0f, 0xee, 0x8e, 0xbc, 0xfd, 0x1b, 0x0b, 0x56, 0x84, 0xe3, 0x60, + 0x50, 0xc3, 0x0c, 0x34, 0x46, 0x64, 0x48, 0xd2, 0x9d, 0x23, 0xca, 0x6e, 0x8e, 0x63, 0xe3, 0x96, + 0xca, 0xa3, 0xb3, 0x26, 0xee, 0x5d, 0x34, 0xf1, 0xae, 0x57, 0x3d, 0x36, 0x5a, 0x59, 0xa1, 0x6b, + 0xbb, 0x9c, 0x74, 0x3e, 0xc9, 0xb7, 0x7e, 0x30, 0xf0, 0x70, 0xf8, 0x83, 0x04, 0xa1, 0x56, 0x95, + 0xd2, 0x73, 0xcd, 0x25, 0x20, 0xaf, 0x67, 0xaa, 0x14, 0x2e, 0xa9, 0x9f, 0xee, 0x1c, 0x1d, 0x30, + 0x5f, 0x95, 0xb9, 0xaa, 0x97, 0x31, 0x2f, 0x44, 0xf9, 0xdc, 0xa8, 0x2a, 0xaf, 0xbb, 0x9c, 0x83, + 0x4d, 0xfd, 0x55, 0xe6, 0x9f, 0x26, 0xbe, 0xbf, 0x04, 0x3d, 0x7d, 0x96, 0x6c, 0x52, 0xc9, 0xf7, + 0x5f, 0xf1, 0x23, 0xa9, 0xec, 0xc7, 0x79, 0xc1, 0x4a, 0xa3, 0xb3, 0x6e, 0x2f, 0xfe, 0xf1, 0x04, + 0x3f, 0x7c, 0xca, 0xec, 0xb2, 0x16, 0xf8, 0x2f, 0x10, 0x27, 0xbb, 0x9d, 0xc7, 0x08, 0x70, 0xdc, + 0x3a, 0x84, 0x5f, 0x48, 0x10, 0x15, 0xcb, 0x1a, 0x10, 0xb9, 0x56, 0x15, 0x3f, 0x15, 0x82, 0x6b, + 0x94, 0xbc, 0xd5, 0x45, 0xb7, 0x86, 0xfd, 0xf4, 0x4e, 0xfe, 0xea, 0xa2, 0x89, 0x93, 0x6d, 0xcc, + 0xb5, 0xa2, 0xb1, 0x2f, 0xba, 0x8d, 0x4d, 0x26, 0x7b, 0x7e, 0x74, 0xac, 0xaa, 0x97, 0x42, 0x1c, + 0xa3, 0x3c, 0x71, 0x9f, 0xc3, 0xd7, 0xc1, 0x43, 0x0d, 0x0b, 0x6e, 0x8d, 0x85, 0x29, 0xbf, 0x41, + 0xec, 0x7e, 0x78, 0x8e, 0x20, 0x45, 0xd4, 0x1f, 0x92, 0xf4, 0xf6, 0x24, 0xd6, 0xb0, 0x38, 0x71, + 0x70, 0x7e, 0xdd, 0x6d, 0x04, 0xf8, 0xd6, 0x61, 0x79, 0x7e, 0xb6, 0xa2, 0xe4, 0x7c, 0x45, 0xc9, + 0xef, 0x15, 0x25, 0x5f, 0xd7, 0xb4, 0x77, 0xbe, 0xa6, 0xbd, 0x9f, 0x6b, 0xda, 0x7b, 0x97, 0x6e, + 0x6e, 0xab, 0x3d, 0xd0, 0xc5, 0x7f, 0x27, 0xda, 0x76, 0x2d, 0x06, 0xed, 0x2d, 0x3d, 0xfd, 0x1b, + 0x00, 0x00, 0xff, 0xff, 0x90, 0xb9, 0xb2, 0x8a, 0xc1, 0x02, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MaxTotalBypassMinFeeMsgGasUsage != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.MaxTotalBypassMinFeeMsgGasUsage)) + i-- + dAtA[i] = 0x18 + } + if len(m.BypassMinFeeMsgTypes) > 0 { + for iNdEx := len(m.BypassMinFeeMsgTypes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.BypassMinFeeMsgTypes[iNdEx]) + copy(dAtA[i:], m.BypassMinFeeMsgTypes[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.BypassMinFeeMsgTypes[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.MinimumGasPrices) > 0 { + for iNdEx := len(m.MinimumGasPrices) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MinimumGasPrices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.MinimumGasPrices) > 0 { + for _, e := range m.MinimumGasPrices { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.BypassMinFeeMsgTypes) > 0 { + for _, s := range m.BypassMinFeeMsgTypes { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.MaxTotalBypassMinFeeMsgGasUsage != 0 { + n += 1 + sovGenesis(uint64(m.MaxTotalBypassMinFeeMsgGasUsage)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinimumGasPrices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MinimumGasPrices = append(m.MinimumGasPrices, types.DecCoin{}) + if err := m.MinimumGasPrices[len(m.MinimumGasPrices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BypassMinFeeMsgTypes", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BypassMinFeeMsgTypes = append(m.BypassMinFeeMsgTypes, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTotalBypassMinFeeMsgGasUsage", wireType) + } + m.MaxTotalBypassMinFeeMsgGasUsage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTotalBypassMinFeeMsgGasUsage |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/globalfee/types/keys.go b/x/globalfee/types/keys.go index 13d6c31ad02..71b43267dd8 100644 --- a/x/globalfee/types/keys.go +++ b/x/globalfee/types/keys.go @@ -1,9 +1,8 @@ package types -// -// const ( -// // ModuleName is the name of the this module -// ModuleName = "globalfee" -// -// QuerierRoute = ModuleName -//) +const ( + // ModuleName is the name of the this module + ModuleName = "globalfee" + + QuerierRoute = ModuleName +) diff --git a/x/globalfee/types/params.go b/x/globalfee/types/params.go index 0e61a2ae41d..dc21409304f 100644 --- a/x/globalfee/types/params.go +++ b/x/globalfee/types/params.go @@ -1,155 +1,156 @@ package types -// import ( -// "fmt" -// "strings" - -// errorsmod "cosmossdk.io/errors" -// sdk "github.com/cosmos/cosmos-sdk/types" -// paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -// gaiaerrors "github.com/cosmos/gaia/v11/types/errors" -// ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" -// ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" -// ) - -// var ( -// // ParamStoreKeyMinGasPrices store key -// ParamStoreKeyMinGasPrices = []byte("MinimumGasPricesParam") -// ParamStoreKeyBypassMinFeeMsgTypes = []byte("BypassMinFeeMsgTypes") -// ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage = []byte("MaxTotalBypassMinFeeMsgGasUsage") - -// // DefaultMinGasPrices is set at runtime to the staking token with zero amount i.e. "0uatom" -// // see DefaultZeroGlobalFee method in gaia/x/globalfee/ante/fee.go. -// DefaultMinGasPrices = sdk.DecCoins{} -// DefaultBypassMinFeeMsgTypes = []string{ -// sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), -// sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}), -// sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeoutOnClose{}), -// } - -// // maxTotalBypassMinFeeMsgGasUsage is the allowed maximum gas usage -// // for all the bypass msgs in a transactions. -// // A transaction that contains only bypass message types and the gas usage does not -// // exceed maxTotalBypassMinFeeMsgGasUsage can be accepted with a zero fee. -// // For details, see gaiafeeante.NewFeeDecorator() -// DefaultmaxTotalBypassMinFeeMsgGasUsage uint64 = 1_000_000 -// ) - -// // DefaultParams returns default parameters -// func DefaultParams() Params { -// return Params{ -// MinimumGasPrices: DefaultMinGasPrices, -// BypassMinFeeMsgTypes: DefaultBypassMinFeeMsgTypes, -// MaxTotalBypassMinFeeMsgGasUsage: DefaultmaxTotalBypassMinFeeMsgGasUsage, -// } -// } - -// func ParamKeyTable() paramtypes.KeyTable { -// return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) -// } - -// // ValidateBasic performs basic validation. -// func (p Params) ValidateBasic() error { -// if err := validateMinimumGasPrices(p.MinimumGasPrices); err != nil { -// return err -// } - -// if err := validateBypassMinFeeMsgTypes(p.BypassMinFeeMsgTypes); err != nil { -// return err -// } - -// return validateMaxTotalBypassMinFeeMsgGasUsage(p.MaxTotalBypassMinFeeMsgGasUsage) -// } - -// // ParamSetPairs returns the parameter set pairs. -// func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { -// return paramtypes.ParamSetPairs{ -// paramtypes.NewParamSetPair( -// ParamStoreKeyMinGasPrices, &p.MinimumGasPrices, validateMinimumGasPrices, -// ), -// paramtypes.NewParamSetPair( -// ParamStoreKeyBypassMinFeeMsgTypes, &p.BypassMinFeeMsgTypes, validateBypassMinFeeMsgTypes, -// ), -// paramtypes.NewParamSetPair( -// ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &p.MaxTotalBypassMinFeeMsgGasUsage, validateMaxTotalBypassMinFeeMsgGasUsage, -// ), -// } -// } - -// func validateMinimumGasPrices(i interface{}) error { -// v, ok := i.(sdk.DecCoins) -// if !ok { -// return errorsmod.Wrapf(gaiaerrors.ErrInvalidType, "type: %T, expected sdk.DecCoins", i) -// } - -// dec := DecCoins(v) -// return dec.Validate() -// } - -// type BypassMinFeeMsgTypes []string +import ( + "fmt" + "strings" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + gaiaerrors "github.com/cosmos/gaia/v11/types/errors" +) + +var ( + // ParamStoreKeyMinGasPrices store key + ParamStoreKeyMinGasPrices = []byte("MinimumGasPricesParam") + ParamStoreKeyBypassMinFeeMsgTypes = []byte("BypassMinFeeMsgTypes") + ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage = []byte("MaxTotalBypassMinFeeMsgGasUsage") + + // DefaultMinGasPrices is set at runtime to the staking token with zero amount i.e. "0uatom" + // see DefaultZeroGlobalFee method in gaia/x/globalfee/ante/fee.go. + DefaultMinGasPrices = sdk.DecCoins{} + DefaultBypassMinFeeMsgTypes = []string{ + sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), + sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeoutOnClose{}), + } + + // maxTotalBypassMinFeeMsgGasUsage is the allowed maximum gas usage + // for all the bypass msgs in a transactions. + // A transaction that contains only bypass message types and the gas usage does not + // exceed maxTotalBypassMinFeeMsgGasUsage can be accepted with a zero fee. + // For details, see gaiafeeante.NewFeeDecorator() + DefaultmaxTotalBypassMinFeeMsgGasUsage uint64 = 1_000_000 +) + +// DefaultParams returns default parameters +func DefaultParams() Params { + return Params{ + MinimumGasPrices: DefaultMinGasPrices, + BypassMinFeeMsgTypes: DefaultBypassMinFeeMsgTypes, + MaxTotalBypassMinFeeMsgGasUsage: DefaultmaxTotalBypassMinFeeMsgGasUsage, + } +} + +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// ValidateBasic performs basic validation. +func (p Params) ValidateBasic() error { + if err := validateMinimumGasPrices(p.MinimumGasPrices); err != nil { + return err + } + + if err := validateBypassMinFeeMsgTypes(p.BypassMinFeeMsgTypes); err != nil { + return err + } + + return validateMaxTotalBypassMinFeeMsgGasUsage(p.MaxTotalBypassMinFeeMsgGasUsage) +} + +// ParamSetPairs returns the parameter set pairs. +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair( + ParamStoreKeyMinGasPrices, &p.MinimumGasPrices, validateMinimumGasPrices, + ), + paramtypes.NewParamSetPair( + ParamStoreKeyBypassMinFeeMsgTypes, &p.BypassMinFeeMsgTypes, validateBypassMinFeeMsgTypes, + ), + paramtypes.NewParamSetPair( + ParamStoreKeyMaxTotalBypassMinFeeMsgGasUsage, &p.MaxTotalBypassMinFeeMsgGasUsage, validateMaxTotalBypassMinFeeMsgGasUsage, + ), + } +} + +func validateMinimumGasPrices(i interface{}) error { + v, ok := i.(sdk.DecCoins) + if !ok { + return errorsmod.Wrapf(gaiaerrors.ErrInvalidType, "type: %T, expected sdk.DecCoins", i) + } + + dec := DecCoins(v) + return dec.Validate() +} + +type BypassMinFeeMsgTypes []string // validateBypassMinFeeMsgTypes checks that bypass msg types aren't empty -// func validateBypassMinFeeMsgTypes(i interface{}) error { -// bypassMinFeeMsgTypes, ok := i.([]string) -// if !ok { -// return errorsmod.Wrapf(gaiaerrors.ErrInvalidType, "type: %T, expected []sdk.Msg", i) -// } - -// for _, msgType := range bypassMinFeeMsgTypes { -// if msgType == "" { -// return fmt.Errorf("invalid empty bypass msg type") -// } - -// if !strings.HasPrefix(msgType, sdk.MsgTypeURL(nil)) { -// return fmt.Errorf("invalid bypass msg type name %s", msgType) -// } -// } - -// return nil -// } - -// func validateMaxTotalBypassMinFeeMsgGasUsage(i interface{}) error { -// _, ok := i.(uint64) -// if !ok { -// return errorsmod.Wrapf(gaiaerrors.ErrInvalidType, "type: %T, expected uint64", i) -// } - -// return nil -// } - -// type DecCoins sdk.DecCoins - -// // Validate checks that the DecCoins are sorted, have nonnegtive amount, with a valid and unique -// // denomination (i.e no duplicates). Otherwise, it returns an error. -// func (coins DecCoins) Validate() error { -// if len(coins) == 0 { -// return nil -// } - -// lowDenom := "" -// seenDenoms := make(map[string]bool) - -// for i, coin := range coins { -// if seenDenoms[coin.Denom] { -// return fmt.Errorf("duplicate denomination %s", coin.Denom) -// } -// if err := sdk.ValidateDenom(coin.Denom); err != nil { -// return err -// } -// // skip the denom order check for the first denom in the coins list -// if i != 0 && coin.Denom <= lowDenom { -// return fmt.Errorf("denomination %s is not sorted", coin.Denom) -// } -// if coin.IsNegative() { -// return fmt.Errorf("coin %s amount is negative", coin.Amount) -// } - -// // we compare each coin against the last denom -// lowDenom = coin.Denom -// seenDenoms[coin.Denom] = true -// } - -// return nil -// } +func validateBypassMinFeeMsgTypes(i interface{}) error { + bypassMinFeeMsgTypes, ok := i.([]string) + if !ok { + return errorsmod.Wrapf(gaiaerrors.ErrInvalidType, "type: %T, expected []sdk.Msg", i) + } + + for _, msgType := range bypassMinFeeMsgTypes { + if msgType == "" { + return fmt.Errorf("invalid empty bypass msg type") + } + + if !strings.HasPrefix(msgType, sdk.MsgTypeURL(nil)) { + return fmt.Errorf("invalid bypass msg type name %s", msgType) + } + } + + return nil +} + +func validateMaxTotalBypassMinFeeMsgGasUsage(i interface{}) error { + _, ok := i.(uint64) + if !ok { + return errorsmod.Wrapf(gaiaerrors.ErrInvalidType, "type: %T, expected uint64", i) + } + + return nil +} + +type DecCoins sdk.DecCoins + +// Validate checks that the DecCoins are sorted, have nonnegtive amount, with a valid and unique +// denomination (i.e no duplicates). Otherwise, it returns an error. +func (coins DecCoins) Validate() error { + if len(coins) == 0 { + return nil + } + + lowDenom := "" + seenDenoms := make(map[string]bool) + + for i, coin := range coins { + if seenDenoms[coin.Denom] { + return fmt.Errorf("duplicate denomination %s", coin.Denom) + } + if err := sdk.ValidateDenom(coin.Denom); err != nil { + return err + } + // skip the denom order check for the first denom in the coins list + if i != 0 && coin.Denom <= lowDenom { + return fmt.Errorf("denomination %s is not sorted", coin.Denom) + } + if coin.IsNegative() { + return fmt.Errorf("coin %s amount is negative", coin.Amount) + } + + // we compare each coin against the last denom + lowDenom = coin.Denom + seenDenoms[coin.Denom] = true + } + + return nil +} diff --git a/x/globalfee/types/params_test.go b/x/globalfee/types/params_test.go index 1f31fe9fd66..b2c2931674a 100644 --- a/x/globalfee/types/params_test.go +++ b/x/globalfee/types/params_test.go @@ -1,157 +1,156 @@ package types -// -// import ( -// "testing" -// -// sdk "github.com/cosmos/cosmos-sdk/types" -// "github.com/stretchr/testify/require" -//) -// -// func TestDefaultParams(t *testing.T) { -// p := DefaultParams() -// require.EqualValues(t, p.MinimumGasPrices, sdk.DecCoins{}) -// require.EqualValues(t, p.BypassMinFeeMsgTypes, DefaultBypassMinFeeMsgTypes) -// require.EqualValues(t, p.MaxTotalBypassMinFeeMsgGasUsage, DefaultmaxTotalBypassMinFeeMsgGasUsage) -//} -// -// func Test_validateMinGasPrices(t *testing.T) { -// tests := map[string]struct { -// coins interface{} -// expectErr bool -// }{ -// "DefaultParams, pass": { -// DefaultParams().MinimumGasPrices, -// false, -// }, -// "DecCoins conversion fails, fail": { -// sdk.Coins{sdk.NewCoin("photon", sdk.OneInt())}, -// true, -// }, -// "coins amounts are zero, pass": { -// sdk.DecCoins{ -// sdk.NewDecCoin("atom", sdk.ZeroInt()), -// sdk.NewDecCoin("photon", sdk.ZeroInt()), -// }, -// false, -// }, -// "duplicate coins denoms, fail": { -// sdk.DecCoins{ -// sdk.NewDecCoin("photon", sdk.OneInt()), -// sdk.NewDecCoin("photon", sdk.OneInt()), -// }, -// true, -// }, -// "coins are not sorted by denom alphabetically, fail": { -// sdk.DecCoins{ -// sdk.NewDecCoin("photon", sdk.OneInt()), -// sdk.NewDecCoin("atom", sdk.OneInt()), -// }, -// true, -// }, -// "negative amount, fail": { -// sdk.DecCoins{ -// sdk.DecCoin{Denom: "photon", Amount: sdk.OneDec().Neg()}, -// }, -// true, -// }, -// "invalid denom, fail": { -// sdk.DecCoins{ -// sdk.DecCoin{Denom: "photon!", Amount: sdk.OneDec().Neg()}, -// }, -// true, -// }, -// } -// -// for name, test := range tests { -// t.Run(name, func(t *testing.T) { -// err := validateMinimumGasPrices(test.coins) -// if test.expectErr { -// require.Error(t, err) -// return -// } -// require.NoError(t, err) -// }) -// } -//} -// -// func Test_validateBypassMinFeeMsgTypes(t *testing.T) { -// tests := map[string]struct { -// msgTypes interface{} -// expectErr bool -// }{ -// "DefaultParams, pass": { -// DefaultParams().BypassMinFeeMsgTypes, -// false, -// }, -// "wrong msg type should make conversion fail, fail": { -// []int{0, 1, 2, 3}, -// true, -// }, -// "empty msg types, pass": { -// []string{}, -// false, -// }, -// "empty msg type, fail": { -// []string{""}, -// true, -// }, -// "invalid msg type name, fail": { -// []string{"ibc.core.channel.v1.MsgRecvPacket"}, -// true, -// }, -// "mixed valid and invalid msgs, fail": { -// []string{ -// "/ibc.core.channel.v1.MsgRecvPacket", -// "", -// }, -// true, -// }, -// } -// -// for name, test := range tests { -// t.Run(name, func(t *testing.T) { -// err := validateBypassMinFeeMsgTypes(test.msgTypes) -// if test.expectErr { -// require.Error(t, err) -// return -// } -// require.NoError(t, err) -// }) -// } -//} -// -// func Test_validateMaxTotalBypassMinFeeMsgGasUsage(t *testing.T) { -// tests := map[string]struct { -// msgTypes interface{} -// expectErr bool -// }{ -// "DefaultParams, pass": { -// DefaultParams().MaxTotalBypassMinFeeMsgGasUsage, -// false, -// }, -// "zero value, pass": { -// uint64(0), -// false, -// }, -// "negative value, fail": { -// -1, -// true, -// }, -// "invalid type, fail": { -// "5", -// true, -// }, -// } -// -// for name, test := range tests { -// t.Run(name, func(t *testing.T) { -// err := validateMaxTotalBypassMinFeeMsgGasUsage(test.msgTypes) -// if test.expectErr { -// require.Error(t, err) -// return -// } -// require.NoError(t, err) -// }) -// } -//} +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestDefaultParams(t *testing.T) { + p := DefaultParams() + require.EqualValues(t, p.MinimumGasPrices, sdk.DecCoins{}) + require.EqualValues(t, p.BypassMinFeeMsgTypes, DefaultBypassMinFeeMsgTypes) + require.EqualValues(t, p.MaxTotalBypassMinFeeMsgGasUsage, DefaultmaxTotalBypassMinFeeMsgGasUsage) +} + +func Test_validateMinGasPrices(t *testing.T) { + tests := map[string]struct { + coins interface{} + expectErr bool + }{ + "DefaultParams, pass": { + DefaultParams().MinimumGasPrices, + false, + }, + "DecCoins conversion fails, fail": { + sdk.Coins{sdk.NewCoin("photon", sdk.OneInt())}, + true, + }, + "coins amounts are zero, pass": { + sdk.DecCoins{ + sdk.NewDecCoin("atom", sdk.ZeroInt()), + sdk.NewDecCoin("photon", sdk.ZeroInt()), + }, + false, + }, + "duplicate coins denoms, fail": { + sdk.DecCoins{ + sdk.NewDecCoin("photon", sdk.OneInt()), + sdk.NewDecCoin("photon", sdk.OneInt()), + }, + true, + }, + "coins are not sorted by denom alphabetically, fail": { + sdk.DecCoins{ + sdk.NewDecCoin("photon", sdk.OneInt()), + sdk.NewDecCoin("atom", sdk.OneInt()), + }, + true, + }, + "negative amount, fail": { + sdk.DecCoins{ + sdk.DecCoin{Denom: "photon", Amount: sdk.OneDec().Neg()}, + }, + true, + }, + "invalid denom, fail": { + sdk.DecCoins{ + sdk.DecCoin{Denom: "photon!", Amount: sdk.OneDec().Neg()}, + }, + true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + err := validateMinimumGasPrices(test.coins) + if test.expectErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func Test_validateBypassMinFeeMsgTypes(t *testing.T) { + tests := map[string]struct { + msgTypes interface{} + expectErr bool + }{ + "DefaultParams, pass": { + DefaultParams().BypassMinFeeMsgTypes, + false, + }, + "wrong msg type should make conversion fail, fail": { + []int{0, 1, 2, 3}, + true, + }, + "empty msg types, pass": { + []string{}, + false, + }, + "empty msg type, fail": { + []string{""}, + true, + }, + "invalid msg type name, fail": { + []string{"ibc.core.channel.v1.MsgRecvPacket"}, + true, + }, + "mixed valid and invalid msgs, fail": { + []string{ + "/ibc.core.channel.v1.MsgRecvPacket", + "", + }, + true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + err := validateBypassMinFeeMsgTypes(test.msgTypes) + if test.expectErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func Test_validateMaxTotalBypassMinFeeMsgGasUsage(t *testing.T) { + tests := map[string]struct { + msgTypes interface{} + expectErr bool + }{ + "DefaultParams, pass": { + DefaultParams().MaxTotalBypassMinFeeMsgGasUsage, + false, + }, + "zero value, pass": { + uint64(0), + false, + }, + "negative value, fail": { + -1, + true, + }, + "invalid type, fail": { + "5", + true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + err := validateMaxTotalBypassMinFeeMsgGasUsage(test.msgTypes) + if test.expectErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/globalfee/types/query.pb.go b/x/globalfee/types/query.pb.go index cb690734b0f..fbf9ed45140 100644 --- a/x/globalfee/types/query.pb.go +++ b/x/globalfee/types/query.pb.go @@ -1,12 +1,21 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: gaia/globalfee/v1/query.proto +// source: gaia/globalfee/v1beta1/query.proto package types import ( + context "context" fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -20,14 +29,508 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -func init() { proto.RegisterFile("gaia/globalfee/v1/query.proto", fileDescriptor_9d905334454049fe) } +// QueryMinimumGasPricesRequest is the request type for the +// Query/MinimumGasPrices RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_12a736cede25d10a, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryMinimumGasPricesResponse is the response type for the +// Query/MinimumGasPrices RPC method. +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_12a736cede25d10a, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "gaia.globalfee.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "gaia.globalfee.v1beta1.QueryParamsResponse") +} + +func init() { + proto.RegisterFile("gaia/globalfee/v1beta1/query.proto", fileDescriptor_12a736cede25d10a) +} + +var fileDescriptor_12a736cede25d10a = []byte{ + // 286 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0x31, 0x4b, 0xc3, 0x40, + 0x14, 0xc7, 0x73, 0xa2, 0x1d, 0xce, 0xed, 0x2c, 0x22, 0x41, 0xce, 0x12, 0x44, 0x8a, 0xc2, 0x1d, + 0xad, 0xab, 0x53, 0x3e, 0x81, 0xd6, 0xcd, 0xed, 0x52, 0x9e, 0x67, 0x20, 0xc9, 0x4b, 0x73, 0x17, + 0xb1, 0xab, 0x9b, 0x9b, 0xd0, 0x2f, 0xd5, 0xb1, 0xe0, 0xe2, 0x24, 0x92, 0xf8, 0x41, 0x24, 0xb9, + 0x20, 0x8a, 0x06, 0xdc, 0x8e, 0x77, 0xbf, 0xf7, 0x7f, 0x3f, 0xfe, 0x34, 0xd0, 0x2a, 0x56, 0x52, + 0x27, 0x18, 0xa9, 0xe4, 0x16, 0x40, 0xde, 0x4f, 0x22, 0xb0, 0x6a, 0x22, 0x17, 0x25, 0x14, 0x4b, + 0x91, 0x17, 0x68, 0x91, 0xed, 0x37, 0x8c, 0xf8, 0x62, 0x44, 0xc7, 0xf8, 0x43, 0x8d, 0x1a, 0x5b, + 0x44, 0x36, 0x2f, 0x47, 0xfb, 0x87, 0x1a, 0x51, 0x27, 0x20, 0x55, 0x1e, 0x4b, 0x95, 0x65, 0x68, + 0x95, 0x8d, 0x31, 0x33, 0xdd, 0xef, 0x71, 0xcf, 0x3d, 0x0d, 0x19, 0x98, 0xb8, 0xa3, 0x82, 0x21, + 0x65, 0x57, 0x8d, 0xc0, 0xa5, 0x2a, 0x54, 0x6a, 0x66, 0xb0, 0x28, 0xc1, 0xd8, 0xe0, 0x9a, 0xee, + 0xfd, 0x98, 0x9a, 0x1c, 0x33, 0x03, 0xec, 0x82, 0x0e, 0xf2, 0x76, 0x72, 0x40, 0x46, 0x64, 0xbc, + 0x3b, 0xe5, 0xe2, 0x6f, 0x5f, 0xe1, 0xf6, 0xc2, 0xed, 0xf5, 0xdb, 0x91, 0x37, 0xeb, 0x76, 0xa6, + 0x2b, 0x42, 0x77, 0xda, 0x54, 0xf6, 0x44, 0xe8, 0xc0, 0x21, 0xec, 0xb4, 0x2f, 0xe2, 0xb7, 0x95, + 0x7f, 0xf6, 0x2f, 0xd6, 0xb9, 0x06, 0x27, 0x8f, 0x2f, 0x1f, 0xab, 0xad, 0x11, 0xe3, 0xb2, 0xa7, + 0x07, 0x67, 0x15, 0x86, 0xeb, 0x8a, 0x93, 0x4d, 0xc5, 0xc9, 0x7b, 0xc5, 0xc9, 0x73, 0xcd, 0xbd, + 0x4d, 0xcd, 0xbd, 0xd7, 0x9a, 0x7b, 0x37, 0x63, 0x1d, 0xdb, 0xbb, 0x32, 0x12, 0x73, 0x4c, 0xe5, + 0x1c, 0x4d, 0x8a, 0xc6, 0x45, 0x3d, 0x7c, 0x0b, 0xb3, 0xcb, 0x1c, 0x4c, 0x34, 0x68, 0xbb, 0x3c, + 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x01, 0xc5, 0x11, 0x71, 0xe3, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/gaia.globalfee.v1beta1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gaia.globalfee.v1beta1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "gaia.globalfee.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "gaia/globalfee/v1beta1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} -var fileDescriptor_9d905334454049fe = []byte{ - // 88 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4d, 0x4f, 0xcc, 0x4c, - 0xd4, 0x4f, 0xcf, 0xc9, 0x4f, 0x4a, 0xcc, 0x49, 0x4b, 0x4d, 0xd5, 0x2f, 0x33, 0xd4, 0x2f, 0x2c, - 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x77, 0x92, 0x38, 0xf1, 0x48, 0x8e, 0xf1, - 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, - 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x24, 0x36, 0xb0, 0x02, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x8e, 0xf4, 0x45, 0x9d, 0x41, 0x00, 0x00, 0x00, +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil } + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/globalfee/types/query.pb.gw.go b/x/globalfee/types/query.pb.gw.go new file mode 100644 index 00000000000..71ec5cbab47 --- /dev/null +++ b/x/globalfee/types/query.pb.gw.go @@ -0,0 +1,153 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: gaia/globalfee/v1beta1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +)