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  }