github.com/Finschia/finschia-sdk@v0.49.1/x/feegrant/filtered_fee.go (about)

     1  package feegrant
     2  
     3  import (
     4  	"github.com/gogo/protobuf/proto"
     5  
     6  	"github.com/Finschia/finschia-sdk/codec/types"
     7  	sdk "github.com/Finschia/finschia-sdk/types"
     8  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
     9  )
    10  
    11  // TODO: Revisit this once we have propoer gas fee framework.
    12  // Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/Finschia/finschia-sdk/discussions/9072
    13  const (
    14  	gasCostPerIteration = uint64(10)
    15  )
    16  
    17  var (
    18  	_ FeeAllowanceI                 = (*AllowedMsgAllowance)(nil)
    19  	_ types.UnpackInterfacesMessage = (*AllowedMsgAllowance)(nil)
    20  )
    21  
    22  // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
    23  func (a *AllowedMsgAllowance) UnpackInterfaces(unpacker types.AnyUnpacker) error {
    24  	var allowance FeeAllowanceI
    25  	return unpacker.UnpackAny(a.Allowance, &allowance)
    26  }
    27  
    28  // NewAllowedMsgFeeAllowance creates new filtered fee allowance.
    29  func NewAllowedMsgAllowance(allowance FeeAllowanceI, allowedMsgs []string) (*AllowedMsgAllowance, error) {
    30  	msg, ok := allowance.(proto.Message)
    31  	if !ok {
    32  		return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", msg)
    33  	}
    34  	any, err := types.NewAnyWithValue(msg)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	return &AllowedMsgAllowance{
    40  		Allowance:       any,
    41  		AllowedMessages: allowedMsgs,
    42  	}, nil
    43  }
    44  
    45  // GetAllowance returns allowed fee allowance.
    46  func (a *AllowedMsgAllowance) GetAllowance() (FeeAllowanceI, error) {
    47  	allowance, ok := a.Allowance.GetCachedValue().(FeeAllowanceI)
    48  	if !ok {
    49  		return nil, sdkerrors.Wrap(ErrNoAllowance, "failed to get allowance")
    50  	}
    51  
    52  	return allowance, nil
    53  }
    54  
    55  // SetAllowance sets allowed fee allowance.
    56  func (a *AllowedMsgAllowance) SetAllowance(allowance FeeAllowanceI) error {
    57  	var err error
    58  	protoAllowance, ok := allowance.(proto.Message)
    59  	if !ok {
    60  		return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", allowance)
    61  	}
    62  	a.Allowance, err = types.NewAnyWithValue(protoAllowance)
    63  	if err != nil {
    64  		return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", protoAllowance)
    65  	}
    66  	return nil
    67  }
    68  
    69  // Accept method checks for the filtered messages has valid expiry
    70  func (a *AllowedMsgAllowance) Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (bool, error) {
    71  	if !a.allMsgTypesAllowed(ctx, msgs) {
    72  		return false, sdkerrors.Wrap(ErrMessageNotAllowed, "message does not exist in allowed messages")
    73  	}
    74  
    75  	allowance, err := a.GetAllowance()
    76  	if err != nil {
    77  		return false, err
    78  	}
    79  
    80  	remove, err := allowance.Accept(ctx, fee, msgs)
    81  	if err == nil && !remove {
    82  		if err = a.SetAllowance(allowance); err != nil {
    83  			return false, err
    84  		}
    85  	}
    86  	return remove, err
    87  }
    88  
    89  func (a *AllowedMsgAllowance) allowedMsgsToMap(ctx sdk.Context) map[string]bool {
    90  	msgsMap := make(map[string]bool, len(a.AllowedMessages))
    91  	for _, msg := range a.AllowedMessages {
    92  		ctx.GasMeter().ConsumeGas(gasCostPerIteration, "check msg")
    93  		msgsMap[msg] = true
    94  	}
    95  
    96  	return msgsMap
    97  }
    98  
    99  func (a *AllowedMsgAllowance) allMsgTypesAllowed(ctx sdk.Context, msgs []sdk.Msg) bool {
   100  	msgsMap := a.allowedMsgsToMap(ctx)
   101  
   102  	for _, msg := range msgs {
   103  		ctx.GasMeter().ConsumeGas(gasCostPerIteration, "check msg")
   104  		if !msgsMap[sdk.MsgTypeURL(msg)] {
   105  			return false
   106  		}
   107  	}
   108  
   109  	return true
   110  }
   111  
   112  // ValidateBasic implements FeeAllowance and enforces basic sanity checks
   113  func (a *AllowedMsgAllowance) ValidateBasic() error {
   114  	if a.Allowance == nil {
   115  		return sdkerrors.Wrap(ErrNoAllowance, "allowance should not be empty")
   116  	}
   117  	if len(a.AllowedMessages) == 0 {
   118  		return sdkerrors.Wrap(ErrNoMessages, "allowed messages shouldn't be empty")
   119  	}
   120  
   121  	allowance, err := a.GetAllowance()
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	return allowance.ValidateBasic()
   127  }