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 }*/