github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/relay.go (about) 1 package keeper 2 3 import ( 4 wasmvmtypes "github.com/CosmWasm/wasmvm/types" 5 //"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/telemetry" 6 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 7 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 8 9 "github.com/fibonacci-chain/fbc/x/wasm/types" 10 ) 11 12 var _ types.IBCContractKeeper = (*Keeper)(nil) 13 14 // OnOpenChannel calls the contract to participate in the IBC channel handshake step. 15 // In the IBC protocol this is either the `Channel Open Init` event on the initiating chain or 16 // `Channel Open Try` on the counterparty chain. 17 // Protocol version and channel ordering should be verified for example. 18 // See https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management 19 func (k Keeper) OnOpenChannel( 20 ctx sdk.Context, 21 contractAddr sdk.AccAddress, 22 msg wasmvmtypes.IBCChannelOpenMsg, 23 ) (string, error) { 24 //defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-open-channel") 25 version := "" 26 _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) 27 if err != nil { 28 return "", err 29 } 30 31 env := types.NewEnv(ctx, contractAddr) 32 querier := k.newQueryHandler(ctx, contractAddr) 33 34 gas := k.runtimeGasForContract(ctx) 35 res, gasUsed, execErr := k.wasmVM.IBCChannelOpen(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) 36 k.consumeRuntimeGas(ctx, gasUsed) 37 if execErr != nil { 38 return "", sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) 39 } 40 41 if res != nil { 42 version = res.Version 43 } 44 45 return version, nil 46 } 47 48 // OnConnectChannel calls the contract to let it know the IBC channel was established. 49 // In the IBC protocol this is either the `Channel Open Ack` event on the initiating chain or 50 // `Channel Open Confirm` on the counterparty chain. 51 // 52 // There is an open issue with the [cosmos-sdk](https://github.com/fibonacci-chain/fbc/libs/cosmos-sdk/issues/8334) 53 // that the counterparty channelID is empty on the initiating chain 54 // See https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management 55 func (k Keeper) OnConnectChannel( 56 ctx sdk.Context, 57 contractAddr sdk.AccAddress, 58 msg wasmvmtypes.IBCChannelConnectMsg, 59 ) error { 60 //defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-connect-channel") 61 contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) 62 if err != nil { 63 return err 64 } 65 66 env := types.NewEnv(ctx, contractAddr) 67 querier := k.newQueryHandler(ctx, contractAddr) 68 69 gas := k.runtimeGasForContract(ctx) 70 res, gasUsed, execErr := k.wasmVM.IBCChannelConnect(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) 71 k.consumeRuntimeGas(ctx, gasUsed) 72 if execErr != nil { 73 return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) 74 } 75 76 return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) 77 } 78 79 // OnCloseChannel calls the contract to let it know the IBC channel is closed. 80 // Calling modules MAY atomically execute appropriate application logic in conjunction with calling chanCloseConfirm. 81 // 82 // Once closed, channels cannot be reopened and identifiers cannot be reused. Identifier reuse is prevented because 83 // we want to prevent potential replay of previously sent packets 84 // See https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management 85 func (k Keeper) OnCloseChannel( 86 ctx sdk.Context, 87 contractAddr sdk.AccAddress, 88 msg wasmvmtypes.IBCChannelCloseMsg, 89 ) error { 90 //defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-close-channel") 91 92 contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) 93 if err != nil { 94 return err 95 } 96 97 params := types.NewEnv(ctx, contractAddr) 98 querier := k.newQueryHandler(ctx, contractAddr) 99 100 gas := k.runtimeGasForContract(ctx) 101 res, gasUsed, execErr := k.wasmVM.IBCChannelClose(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) 102 k.consumeRuntimeGas(ctx, gasUsed) 103 if execErr != nil { 104 return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) 105 } 106 107 return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) 108 } 109 110 // OnRecvPacket calls the contract to process the incoming IBC packet. The contract fully owns the data processing and 111 // returns the acknowledgement data for the chain level. This allows custom applications and protocols on top 112 // of IBC. Although it is recommended to use the standard acknowledgement envelope defined in 113 // https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope 114 // 115 // For more information see: https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling 116 func (k Keeper) OnRecvPacket( 117 ctx sdk.Context, 118 contractAddr sdk.AccAddress, 119 msg wasmvmtypes.IBCPacketReceiveMsg, 120 ) ([]byte, error) { 121 //defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-recv-packet") 122 contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) 123 if err != nil { 124 return nil, err 125 } 126 127 env := types.NewEnv(ctx, contractAddr) 128 querier := k.newQueryHandler(ctx, contractAddr) 129 130 gas := k.runtimeGasForContract(ctx) 131 res, gasUsed, execErr := k.wasmVM.IBCPacketReceive(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) 132 k.consumeRuntimeGas(ctx, gasUsed) 133 if execErr != nil { 134 return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) 135 } 136 if res.Err != "" { // handle error case as before https://github.com/CosmWasm/wasmvm/commit/c300106fe5c9426a495f8e10821e00a9330c56c6 137 return nil, sdkerrors.Wrap(types.ErrExecuteFailed, res.Err) 138 } 139 // note submessage reply results can overwrite the `Acknowledgement` data 140 return k.handleContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Acknowledgement, res.Ok.Events) 141 } 142 143 // OnAckPacket calls the contract to handle the "acknowledgement" data which can contain success or failure of a packet 144 // acknowledgement written on the receiving chain for example. This is application level data and fully owned by the 145 // contract. The use of the standard acknowledgement envelope is recommended: https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope 146 // 147 // On application errors the contract can revert an operation like returning tokens as in ibc-transfer. 148 // 149 // For more information see: https://github.com/fibonacci-chain/fbc/libs/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling 150 func (k Keeper) OnAckPacket( 151 ctx sdk.Context, 152 contractAddr sdk.AccAddress, 153 msg wasmvmtypes.IBCPacketAckMsg, 154 ) error { 155 //defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-ack-packet") 156 contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) 157 if err != nil { 158 return err 159 } 160 161 env := types.NewEnv(ctx, contractAddr) 162 querier := k.newQueryHandler(ctx, contractAddr) 163 164 gas := k.runtimeGasForContract(ctx) 165 res, gasUsed, execErr := k.wasmVM.IBCPacketAck(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) 166 k.consumeRuntimeGas(ctx, gasUsed) 167 if execErr != nil { 168 return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) 169 } 170 return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) 171 } 172 173 // OnTimeoutPacket calls the contract to let it know the packet was never received on the destination chain within 174 // the timeout boundaries. 175 // The contract should handle this on the application level and undo the original operation 176 func (k Keeper) OnTimeoutPacket( 177 ctx sdk.Context, 178 contractAddr sdk.AccAddress, 179 msg wasmvmtypes.IBCPacketTimeoutMsg, 180 ) error { 181 //defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-timeout-packet") 182 183 contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) 184 if err != nil { 185 return err 186 } 187 188 env := types.NewEnv(ctx, contractAddr) 189 querier := k.newQueryHandler(ctx, contractAddr) 190 191 gas := k.runtimeGasForContract(ctx) 192 res, gasUsed, execErr := k.wasmVM.IBCPacketTimeout(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) 193 k.consumeRuntimeGas(ctx, gasUsed) 194 if execErr != nil { 195 return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) 196 } 197 198 return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) 199 } 200 201 func (k Keeper) handleIBCBasicContractResponse(ctx sdk.Context, addr sdk.AccAddress, id string, res *wasmvmtypes.IBCBasicResponse) error { 202 _, err := k.handleContractResponse(ctx, addr, id, res.Messages, res.Attributes, nil, res.Events) 203 return err 204 }