Skip to content

Commit

Permalink
feat: add feehub module
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonberg1997 committed Dec 22, 2022
1 parent 5327b6e commit ebce19e
Show file tree
Hide file tree
Showing 24 changed files with 2,309 additions and 0 deletions.
18 changes: 18 additions & 0 deletions proto/cosmos/feehub/v1alpha1/feehub.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";
package cosmos.feehub.v1alpha1;

import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/feehub/types";

// Params defines the parameters for the feehub module.
message Params {
option (gogoproto.equal) = true;
option (gogoproto.goproto_stringer) = false;

uint64 max_tx_size = 1 [(gogoproto.customname) = "MaxTxSize"];
uint64 min_gas_per_byte = 2 [(gogoproto.customname) = "MinGasPerByte"];
uint64 msg_send_gas = 3 [(gogoproto.customname) = "MsgSendGas"];
}
14 changes: 14 additions & 0 deletions proto/cosmos/feehub/v1alpha1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
syntax = "proto3";
package cosmos.feehub.v1alpha1;

import "google/protobuf/any.proto";
import "gogoproto/gogo.proto";
import "cosmos/feehub/v1alpha1/feehub.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/feehub/types";

// GenesisState defines the feehub module's genesis state.
message GenesisState {
// params defines all the paramaters of the module.
Params params = 1 [(gogoproto.nullable) = false];
}
27 changes: 27 additions & 0 deletions proto/cosmos/feehub/v1alpha1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
syntax = "proto3";
package cosmos.feehub.v1alpha1;

import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "cosmos/feehub/v1alpha1/feehub.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/feehub/types";

// Query defines the gRPC querier service.
service Query {
// Params queries all parameters.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/cosmos/feehub/v1alpha1/params";
}
}

// QueryParamsRequest is the request type for the Query/Params RPC method.
message QueryParamsRequest {}

// QueryParamsResponse is the response type for the Query/Params RPC method.
message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];
}
5 changes: 5 additions & 0 deletions x/auth/ante/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ante
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
feehubtypes "github.com/cosmos/cosmos-sdk/x/feehub/types"
)

// AccountKeeper defines the contract needed for AccountKeeper related APIs.
Expand All @@ -18,3 +19,7 @@ type AccountKeeper interface {
type FeegrantKeeper interface {
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
}

type FeehubKeeper interface {
GetParams(ctx sdk.Context) (params feehubtypes.Params)
}
108 changes: 108 additions & 0 deletions x/auth/ante/msg_fee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package ante

import (
"cosmossdk.io/errors"

"github.com/cosmos/cosmos-sdk/codec/legacy"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
)

// ConsumeMsgGasDecorator will take in parameters and consume gas depending on
// the size of tx and msg type before calling next AnteHandler.
//
// CONTRACT: If simulate=true, then signatures must either be completely filled
// in or empty.
type ConsumeMsgGasDecorator struct {
ak AccountKeeper
fhk FeehubKeeper
}

func NewConsumeMsgGasDecorator(ak AccountKeeper, fhk FeehubKeeper) ConsumeMsgGasDecorator {
return ConsumeMsgGasDecorator{
ak: ak,
fhk: fhk,
}
}

func (cmfg ConsumeMsgGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, errors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
}

params := cmfg.fhk.GetParams(ctx)
txBytesLength := uint64(len(ctx.TxBytes()))

msgGas, err := cmfg.getMsgGas(params, sigTx)
if err != nil {
return ctx, err
}

// simulate gas cost for signatures in simulate mode
if simulate {
// in simulate mode, each element should be a nil signature
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
}
n := len(sigs)

for i, signer := range sigTx.GetSigners() {
// if signature is already filled in, no need to simulate gas cost
if i < n && !isIncompleteSignature(sigs[i].Data) {
continue
}

var pubkey cryptotypes.PubKey

acc := cmfg.ak.GetAccount(ctx, signer)

// use placeholder simSecp256k1Pubkey if sig is nil
if acc == nil || acc.GetPubKey() == nil {
pubkey = simSecp256k1Pubkey
} else {
pubkey = acc.GetPubKey()
}

// use stdsignature to mock the size of a full signature
simSig := legacytx.StdSignature{ //nolint:staticcheck // this will be removed when proto is ready
Signature: simSecp256k1Sig[:],
PubKey: pubkey,
}

sigBz := legacy.Cdc.MustMarshal(simSig)
txBytesLength = txBytesLength + uint64(len(sigBz)) + 6
}
}

if txBytesLength > params.GetMaxTxSize() {
return ctx, errors.Wrapf(sdkerrors.ErrTxTooLarge, "tx length: %d, limit: %d", txBytesLength, params.GetMaxTxSize())
}

gasByByteLength := txBytesLength * params.GetMinGasPerByte()
if gasByByteLength >= msgGas {
ctx.GasMeter().ConsumeGas(gasByByteLength, "gas by tx byte length")
} else {
ctx.GasMeter().ConsumeGas(msgGas, "msg gas")
}

return next(ctx, tx, simulate)
}

func (cmfg ConsumeMsgGasDecorator) getMsgGas(params types.Params, tx sdk.Tx) (uint64, error) {
msg := tx.GetMsgs()[0]
switch msg := msg.(type) {
case *banktypes.MsgSend:
feeCalcGen := types.GetCalculatorGen(msg.Type())
feeCalc := feeCalcGen(params)
return feeCalc(msg), nil
default:
return 0, errors.Wrapf(sdkerrors.ErrInvalidType, "unrecognized msg type: %T", msg)
}
}
58 changes: 58 additions & 0 deletions x/feehub/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cli

import (
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
"github.com/spf13/cobra"
)

// GetQueryCmd returns the transaction commands for this module
func GetQueryCmd() *cobra.Command {
cmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the feehub module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

cmd.AddCommand(
QueryParamsCmd(),
)

return cmd
}

// QueryParamsCmd returns the command handler for evidence parameter querying.
func QueryParamsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Short: "Query the current feehub parameters",
Args: cobra.NoArgs,
Long: strings.TrimSpace(`Query the current feehub parameters:
$ <appd> query feehub params
`),
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
}
21 changes: 21 additions & 0 deletions x/feehub/keeper/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
)

// InitGenesis - Init store state from genesis data
//
// CONTRACT: old coins from the FeeCollectionKeeper need to be transferred through
// a genesis port script to the new fee collector account
func (fhk FeehubKeeper) InitGenesis(ctx sdk.Context, data types.GenesisState) {
fhk.SetParams(ctx, data.Params)
}

// ExportGenesis returns a GenesisState for a given context and keeper
func (fhk FeehubKeeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
params := fhk.GetParams(ctx)

return types.NewGenesisState(params)
}
24 changes: 24 additions & 0 deletions x/feehub/keeper/grpc_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package keeper

import (
"context"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
)

var _ types.QueryServer = FeehubKeeper{}

// Params returns parameters of auth module
func (fhk FeehubKeeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
params := fhk.GetParams(ctx)

return &types.QueryParamsResponse{Params: params}, nil
}
43 changes: 43 additions & 0 deletions x/feehub/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package keeper

import (
"github.com/tendermint/tendermint/libs/log"

"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)

// FeehubKeeper encodes/decodes accounts using the go-amino (binary)
// encoding/decoding library.
type FeehubKeeper struct {
key storetypes.StoreKey
cdc codec.BinaryCodec
paramSubspace paramtypes.Subspace
}

// NewFeehubKeeper returns a new feehub keeper
func NewFeehubKeeper(
cdc codec.BinaryCodec, key storetypes.StoreKey, paramstore paramtypes.Subspace,
) FeehubKeeper {
// set KeyTable if it has not already been set
if !paramstore.HasKeyTable() {
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
}

return FeehubKeeper{
key: key,
cdc: cdc,
paramSubspace: paramstore,
}
}

// Logger returns a module-specific logger.
func (fhk FeehubKeeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+types.ModuleName)
}

// GetCodec return codec.Codec object used by the keeper
func (fhk FeehubKeeper) GetCodec() codec.BinaryCodec { return fhk.cdc }
17 changes: 17 additions & 0 deletions x/feehub/keeper/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
)

// SetParams sets the auth module's parameters.
func (fhk FeehubKeeper) SetParams(ctx sdk.Context, params types.Params) {
fhk.paramSubspace.SetParamSet(ctx, &params)
}

// GetParams gets the auth module's parameters.
func (fhk FeehubKeeper) GetParams(ctx sdk.Context) (params types.Params) {
fhk.paramSubspace.GetParamSet(ctx, &params)
return
}
34 changes: 34 additions & 0 deletions x/feehub/keeper/querier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package keeper

import (
abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/feehub/types"
)

// NewQuerier creates a querier for auth REST endpoints
func NewQuerier(k FeehubKeeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
switch path[0] {
case types.QueryParams:
return queryParams(ctx, k, legacyQuerierCdc)

default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0])
}
}
}

func queryParams(ctx sdk.Context, k FeehubKeeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
params := k.GetParams(ctx)

res, err := codec.MarshalJSONIndent(legacyQuerierCdc, params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}

return res, nil
}
Loading

0 comments on commit ebce19e

Please sign in to comment.