github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/handler_plugin.go (about)

     1  package keeper
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	wasmvmtypes "github.com/CosmWasm/wasmvm/types"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/baseapp"
     9  	codectypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types"
    10  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    11  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    12  	ibcadapter "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/ibc-adapter"
    13  	channeltypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
    14  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    15  
    16  	"github.com/fibonacci-chain/fbc/x/wasm/types"
    17  )
    18  
    19  // msgEncoder is an extension point to customize encodings
    20  type msgEncoder interface {
    21  	// Encode converts wasmvm message to n cosmos message types
    22  	Encode(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]ibcadapter.Msg, error)
    23  }
    24  
    25  // MessageRouter ADR 031 request type routing
    26  type MessageRouter interface {
    27  	Handler(methodName string) baseapp.MsgServiceHandler
    28  }
    29  
    30  // SDKMessageHandler can handles messages that can be encoded into sdk.Message types and routed.
    31  type SDKMessageHandler struct {
    32  	router   MessageRouter
    33  	encoders msgEncoder
    34  }
    35  
    36  func NewDefaultMessageHandler(
    37  	router MessageRouter,
    38  	channelKeeper types.ChannelKeeper,
    39  	capabilityKeeper types.CapabilityKeeper,
    40  	//bankKeeper types.Burner,
    41  	unpacker codectypes.AnyUnpacker,
    42  	portSource types.ICS20TransferPortSource,
    43  	customEncoders ...*MessageEncoders,
    44  ) Messenger {
    45  	encoders := DefaultEncoders(unpacker, portSource)
    46  	for _, e := range customEncoders {
    47  		encoders = encoders.Merge(e)
    48  	}
    49  	return NewMessageHandlerChain(
    50  		NewSDKMessageHandler(router, encoders),
    51  		//NewIBCRawPacketHandler(channelKeeper, capabilityKeeper),
    52  		// un use burn coin message
    53  		//NewBurnCoinMessageHandler(bankKeeper),
    54  	)
    55  }
    56  
    57  func NewSDKMessageHandler(router MessageRouter, encoders msgEncoder) SDKMessageHandler {
    58  	return SDKMessageHandler{
    59  		router:   router,
    60  		encoders: encoders,
    61  	}
    62  }
    63  
    64  func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
    65  	sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg)
    66  	if err != nil {
    67  		return nil, nil, err
    68  	}
    69  	for _, sdkMsg := range sdkMsgs {
    70  		res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg)
    71  		if err != nil {
    72  			return nil, nil, err
    73  		}
    74  		// append data
    75  		data = append(data, res.Data)
    76  		// append events
    77  		sdkEvents := make([]sdk.Event, len(res.Events))
    78  		for i := range res.Events {
    79  			sdkEvents[i] = sdk.Event(res.Events[i])
    80  		}
    81  		events = append(events, sdkEvents...)
    82  	}
    83  	return
    84  }
    85  
    86  func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg ibcadapter.Msg) (*sdk.Result, error) {
    87  	if err := msg.ValidateBasic(); err != nil {
    88  		return nil, err
    89  	}
    90  	// make sure this account can send it
    91  	for _, acct := range msg.GetSigners() {
    92  		if !acct.Equals(contractAddr) {
    93  			return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission")
    94  		}
    95  	}
    96  
    97  	// find the handler and execute it
    98  	msgUrl := ibcadapter.MsgTypeURL(msg)
    99  	if handler := h.router.Handler(msgUrl); handler != nil {
   100  		// ADR 031 request type routing
   101  		msgResult, err := handler(ctx, msg)
   102  		return msgResult, err
   103  	}
   104  	// legacy sdk.Msg routing
   105  	// Assuming that the app developer has migrated all their Msgs to
   106  	// proto messages and has registered all `Msg services`, then this
   107  	// path should never be called, because all those Msgs should be
   108  	// registered within the `msgServiceRouter` already.
   109  	return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg)
   110  }
   111  
   112  // MessageHandlerChain defines a chain of handlers that are called one by one until it can be handled.
   113  type MessageHandlerChain struct {
   114  	handlers []Messenger
   115  }
   116  
   117  func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandlerChain {
   118  	r := &MessageHandlerChain{handlers: append([]Messenger{first}, others...)}
   119  	for i := range r.handlers {
   120  		if r.handlers[i] == nil {
   121  			panic(fmt.Sprintf("handler must not be nil at position : %d", i))
   122  		}
   123  	}
   124  	return r
   125  }
   126  
   127  // DispatchMsg dispatch message and calls chained handlers one after another in
   128  // order to find the right one to process given message. If a handler cannot
   129  // process given message (returns ErrUnknownMsg), its result is ignored and the
   130  // next handler is executed.
   131  func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) {
   132  	for _, h := range m.handlers {
   133  		events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
   134  		switch {
   135  		case err == nil:
   136  			return events, data, nil
   137  		case errors.Is(err, types.ErrUnknownMsg):
   138  			continue
   139  		default:
   140  			return events, data, err
   141  		}
   142  	}
   143  	return nil, nil, sdkerrors.Wrap(types.ErrUnknownMsg, "no handler found")
   144  }
   145  
   146  // IBCRawPacketHandler handels IBC.SendPacket messages which are published to an IBC channel.
   147  type IBCRawPacketHandler struct {
   148  	channelKeeper    types.ChannelKeeper
   149  	capabilityKeeper types.CapabilityKeeper
   150  }
   151  
   152  func NewIBCRawPacketHandler(chk types.ChannelKeeper, cak types.CapabilityKeeper) IBCRawPacketHandler {
   153  	return IBCRawPacketHandler{channelKeeper: chk, capabilityKeeper: cak}
   154  }
   155  
   156  // DispatchMsg publishes a raw IBC packet onto the channel.
   157  func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
   158  	if msg.IBC == nil || msg.IBC.SendPacket == nil {
   159  		return nil, nil, types.ErrUnknownMsg
   160  	}
   161  	if contractIBCPortID == "" {
   162  		return nil, nil, sdkerrors.Wrapf(types.ErrUnsupportedForContract, "ibc not supported")
   163  	}
   164  	contractIBCChannelID := msg.IBC.SendPacket.ChannelID
   165  	if contractIBCChannelID == "" {
   166  		return nil, nil, sdkerrors.Wrapf(types.ErrEmpty, "ibc channel")
   167  	}
   168  
   169  	sequence, found := h.channelKeeper.GetNextSequenceSend(ctx, contractIBCPortID, contractIBCChannelID)
   170  	if !found {
   171  		return nil, nil, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound,
   172  			"source port: %s, source channel: %s", contractIBCPortID, contractIBCChannelID,
   173  		)
   174  	}
   175  
   176  	channelInfo, ok := h.channelKeeper.GetChannel(ctx, contractIBCPortID, contractIBCChannelID)
   177  	if !ok {
   178  		return nil, nil, sdkerrors.Wrap(channeltypes.ErrInvalidChannel, "not found")
   179  	}
   180  	channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID))
   181  	if !ok {
   182  		return nil, nil, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability")
   183  	}
   184  	packet := channeltypes.NewPacket(
   185  		msg.IBC.SendPacket.Data,
   186  		sequence,
   187  		contractIBCPortID,
   188  		contractIBCChannelID,
   189  		channelInfo.Counterparty.PortId,
   190  		channelInfo.Counterparty.ChannelId,
   191  		ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block),
   192  		msg.IBC.SendPacket.Timeout.Timestamp,
   193  	)
   194  	return nil, nil, h.channelKeeper.SendPacket(ctx, channelCap, packet)
   195  }
   196  
   197  var _ Messenger = MessageHandlerFunc(nil)
   198  
   199  // MessageHandlerFunc is a helper to construct a function based message handler.
   200  type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error)
   201  
   202  // DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc.
   203  func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
   204  	return m(ctx, contractAddr, contractIBCPortID, msg)
   205  }
   206  
   207  // NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages
   208  /*func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc {
   209  	return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
   210  		if msg.Bank != nil && msg.Bank.Burn != nil {
   211  			coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount)
   212  			if err != nil {
   213  				return nil, nil, err
   214  			}
   215  			if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil {
   216  				return nil, nil, sdkerrors.Wrap(err, "transfer to module")
   217  			}
   218  			if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil {
   219  				return nil, nil, sdkerrors.Wrap(err, "burn coins")
   220  			}
   221  			moduleLogger(ctx).Info("Burned", "amount", coins)
   222  			return nil, nil, nil
   223  		}
   224  		return nil, nil, types.ErrUnknownMsg
   225  	}
   226  }*/