mukan-ibc/testing/endpoint.go
Mukan Erkin Törük 88dd97a9f8
Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:22 +03:00

709 lines
27 KiB
Go

package ibctesting
import (
"errors"
"fmt"
"strings"
"github.com/stretchr/testify/require"
"git.cw.tr/mukan-network/mukan-sdk/baseapp"
abci "git.cw.tr/mukan-network/mukan-consensus/abci/types"
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
connectiontypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/03-connection/types"
channeltypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/types"
commitmenttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/23-commitment/types"
commitmenttypesv2 "git.cw.tr/mukan-network/mukan-ibc/modules/core/23-commitment/types/v2"
host "git.cw.tr/mukan-network/mukan-ibc/modules/core/24-host"
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
ibctm "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/07-tendermint"
)
// Endpoint is a which represents a channel endpoint and its associated
// client and connections. It contains client, connection, and channel
// configuration parameters. Endpoint functions will utilize the parameters
// set in the configuration structs when executing IBC messages.
type Endpoint struct {
Chain *TestChain
Counterparty *Endpoint
ClientID string
ConnectionID string
ChannelID string
ClientConfig ClientConfig
ConnectionConfig *ConnectionConfig
ChannelConfig *ChannelConfig
MerklePathPrefix commitmenttypesv2.MerklePath
// disableUniqueChannelIDs is used to enforce, in a test,
// the old way to generate channel IDs (all channels are called channel-0)
// It is used only by one test suite and should not be used for new tests.
disableUniqueChannelIDs bool
}
// NewEndpoint constructs a new endpoint without the counterparty.
// CONTRACT: the counterparty endpoint must be set by the caller.
func NewEndpoint(
chain *TestChain, clientConfig ClientConfig,
connectionConfig *ConnectionConfig, channelConfig *ChannelConfig,
) *Endpoint {
return &Endpoint{
Chain: chain,
ClientConfig: clientConfig,
ConnectionConfig: connectionConfig,
ChannelConfig: channelConfig,
MerklePathPrefix: MerklePath,
}
}
// NewDefaultEndpoint constructs a new endpoint using default values.
// CONTRACT: the counterparty endpoitn must be set by the caller.
func NewDefaultEndpoint(chain *TestChain) *Endpoint {
return &Endpoint{
Chain: chain,
ClientConfig: NewTendermintConfig(),
ConnectionConfig: NewConnectionConfig(),
ChannelConfig: NewChannelConfig(),
MerklePathPrefix: MerklePath,
}
}
// QueryProof queries proof associated with this endpoint using the latest client state
// height on the counterparty chain.
func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) {
// obtain the counterparty client height.
latestCounterpartyHeight := endpoint.Counterparty.GetClientLatestHeight()
// query proof on the counterparty using the latest height of the IBC client
return endpoint.QueryProofAtHeight(key, latestCounterpartyHeight.GetRevisionHeight())
}
// QueryProofAtHeight queries proof associated with this endpoint using the proof height
// provided
func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) {
// query proof on the counterparty using the latest height of the IBC client
return endpoint.Chain.QueryProofAtHeight(key, int64(height))
}
// CreateClient creates an IBC client on the endpoint. It will update the
// clientID for the endpoint if the message is successfully executed.
// NOTE: a solo machine client will be created with an empty diversifier.
func (endpoint *Endpoint) CreateClient() (err error) {
// ensure counterparty has committed state
endpoint.Counterparty.Chain.NextBlock()
var (
clientState exported.ClientState
consensusState exported.ConsensusState
)
switch endpoint.ClientConfig.GetClientType() {
case exported.Tendermint:
tmConfig, ok := endpoint.ClientConfig.(*TendermintConfig)
require.True(endpoint.Chain.TB, ok)
height, ok := endpoint.Counterparty.Chain.LatestCommittedHeader.GetHeight().(clienttypes.Height)
require.True(endpoint.Chain.TB, ok)
clientState = ibctm.NewClientState(
endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift,
height, commitmenttypes.GetSDKSpecs(), UpgradePath)
consensusState = endpoint.Counterparty.Chain.LatestCommittedHeader.ConsensusState()
case exported.Solomachine:
// TODO
// solo := NewSolomachine(endpoint.Chain.TB, endpoint.Chain.Codec, clientID, "", 1)
// clientState = solo.ClientState()
// consensusState = solo.ConsensusState()
default:
err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType())
}
if err != nil {
return err
}
msg, err := clienttypes.NewMsgCreateClient(
clientState, consensusState, endpoint.Chain.SenderAccount.GetAddress().String(),
)
require.NoError(endpoint.Chain.TB, err)
res, err := endpoint.Chain.SendMsgs(msg)
if err != nil {
return err
}
endpoint.ClientID, err = ParseClientIDFromEvents(res.Events)
require.NoError(endpoint.Chain.TB, err)
return nil
}
// UpdateClient updates the IBC client associated with the endpoint.
func (endpoint *Endpoint) UpdateClient() (err error) {
// ensure counterparty has committed state
endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain)
var header exported.ClientMessage
switch endpoint.ClientConfig.GetClientType() {
case exported.Tendermint:
trustedHeight, ok := endpoint.GetClientLatestHeight().(clienttypes.Height)
require.True(endpoint.Chain.TB, ok)
header, err = endpoint.Counterparty.Chain.IBCClientHeader(endpoint.Counterparty.Chain.LatestCommittedHeader, trustedHeight)
default:
err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType())
}
if err != nil {
return err
}
msg, err := clienttypes.NewMsgUpdateClient(
endpoint.ClientID, header,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
require.NoError(endpoint.Chain.TB, err)
return endpoint.Chain.sendMsgs(msg)
}
// FreezeClient freezes the IBC client associated with the endpoint.
func (endpoint *Endpoint) FreezeClient() {
clientState := endpoint.Chain.GetClientState(endpoint.ClientID)
tmClientState, ok := clientState.(*ibctm.ClientState)
require.True(endpoint.Chain.TB, ok)
tmClientState.FrozenHeight = clienttypes.NewHeight(0, 1)
endpoint.Chain.App.GetIBCKeeper().ClientKeeper.SetClientState(endpoint.Chain.GetContext(), endpoint.ClientID, tmClientState)
}
// UpgradeChain will upgrade a chain's chainID to the next revision number.
// It will also update the counterparty client.
// TODO: implement actual upgrade chain functionality via scheduling an upgrade
// and upgrading the client via MsgUpgradeClient
// see reference https://github.com/cosmos/ibc-go/pull/1169
func (endpoint *Endpoint) UpgradeChain() error {
if strings.TrimSpace(endpoint.Counterparty.ClientID) == "" {
return errors.New("cannot upgrade chain if there is no counterparty client")
}
clientState := endpoint.Counterparty.GetClientState()
tmClientState, ok := clientState.(*ibctm.ClientState)
require.True(endpoint.Chain.TB, ok)
// increment revision number in chainID
oldChainID := tmClientState.ChainId
if !clienttypes.IsRevisionFormat(oldChainID) {
return fmt.Errorf("cannot upgrade chain which is not of revision format: %s", oldChainID)
}
revisionNumber := clienttypes.ParseChainID(oldChainID)
newChainID, err := clienttypes.SetRevisionNumber(oldChainID, revisionNumber+1)
if err != nil {
return err
}
// update chain
baseapp.SetChainID(newChainID)(endpoint.Chain.App.GetBaseApp())
endpoint.Chain.ChainID = newChainID
endpoint.Chain.ProposedHeader.ChainID = newChainID
endpoint.Chain.NextBlock() // commit changes
// update counterparty client manually
tmClientState.ChainId = newChainID
tmClientState.LatestHeight = clienttypes.NewHeight(revisionNumber+1, tmClientState.LatestHeight.GetRevisionHeight()+1)
endpoint.Counterparty.SetClientState(clientState)
tmConsensusState := &ibctm.ConsensusState{
Timestamp: endpoint.Chain.LatestCommittedHeader.GetTime(),
Root: commitmenttypes.NewMerkleRoot(endpoint.Chain.LatestCommittedHeader.Header.GetAppHash()),
NextValidatorsHash: endpoint.Chain.LatestCommittedHeader.Header.NextValidatorsHash,
}
latestHeight := endpoint.Counterparty.GetClientLatestHeight()
endpoint.Counterparty.SetConsensusState(tmConsensusState, latestHeight)
// ensure the next update isn't identical to the one set in state
endpoint.Chain.Coordinator.IncrementTime()
endpoint.Chain.NextBlock()
return endpoint.Counterparty.UpdateClient()
}
// ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint.
func (endpoint *Endpoint) ConnOpenInit() error {
msg := connectiontypes.NewMsgConnectionOpenInit(
endpoint.ClientID,
endpoint.Counterparty.ClientID,
endpoint.Counterparty.Chain.GetPrefix(), DefaultOpenInitVersion, endpoint.ConnectionConfig.DelayPeriod,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
res, err := endpoint.Chain.SendMsgs(msg)
if err != nil {
return err
}
endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.Events)
require.NoError(endpoint.Chain.TB, err)
return nil
}
// ConnOpenTry will construct and execute a MsgConnectionOpenTry on the associated endpoint.
func (endpoint *Endpoint) ConnOpenTry() error {
err := endpoint.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
initProof, proofHeight := endpoint.QueryConnectionHandshakeProof()
msg := connectiontypes.NewMsgConnectionOpenTry(
endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID,
endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ConnectionVersion},
endpoint.ConnectionConfig.DelayPeriod, initProof, proofHeight,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
res, err := endpoint.Chain.SendMsgs(msg)
if err != nil {
return err
}
if endpoint.ConnectionID == "" {
endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.Events)
require.NoError(endpoint.Chain.TB, err)
}
return nil
}
// ConnOpenAck will construct and execute a MsgConnectionOpenAck on the associated endpoint.
func (endpoint *Endpoint) ConnOpenAck() error {
err := endpoint.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
tryProof, proofHeight := endpoint.QueryConnectionHandshakeProof()
msg := connectiontypes.NewMsgConnectionOpenAck(
endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, // testing doesn't use flexible selection
tryProof, proofHeight, ConnectionVersion,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
return endpoint.Chain.sendMsgs(msg)
}
// ConnOpenConfirm will construct and execute a MsgConnectionOpenConfirm on the associated endpoint.
func (endpoint *Endpoint) ConnOpenConfirm() error {
err := endpoint.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID)
proof, height := endpoint.Counterparty.Chain.QueryProof(connectionKey)
msg := connectiontypes.NewMsgConnectionOpenConfirm(
endpoint.ConnectionID,
proof, height,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
return endpoint.Chain.sendMsgs(msg)
}
// QueryConnectionHandshakeProof returns all the proofs necessary to execute OpenTry or Open Ack of
// the connection handshakes. It returns the proof of the counterparty connection and the proof height.
func (endpoint *Endpoint) QueryConnectionHandshakeProof() (
connectionProof []byte, proofHeight clienttypes.Height,
) {
// query proof for the connection on the counterparty
connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID)
connectionProof, proofHeight = endpoint.Counterparty.QueryProof(connectionKey)
return connectionProof, proofHeight
}
var sequenceNumber int
// IncrementNextChannelSequence incrementes the value "nextChannelSequence" in the store,
// which is used to determine the next channel ID.
// This guarantees that we'll have always different IDs while running tests.
func (endpoint *Endpoint) IncrementNextChannelSequence() {
if endpoint.disableUniqueChannelIDs {
return
}
sequenceNumber++
endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetNextChannelSequence(endpoint.Chain.GetContext(), uint64(sequenceNumber))
}
// ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint.
func (endpoint *Endpoint) ChanOpenInit() error {
endpoint.IncrementNextChannelSequence()
msg := channeltypes.NewMsgChannelOpenInit(
endpoint.ChannelConfig.PortID,
endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID},
endpoint.Counterparty.ChannelConfig.PortID,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
res, err := endpoint.Chain.SendMsgs(msg)
if err != nil {
return err
}
endpoint.ChannelID, err = ParseChannelIDFromEvents(res.Events)
require.NoError(endpoint.Chain.TB, err)
// update version to selected app version
// NOTE: this update must be performed after SendMsgs()
endpoint.ChannelConfig.Version = endpoint.GetChannel().Version
endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version
return nil
}
// ChanOpenTry will construct and execute a MsgChannelOpenTry on the associated endpoint.
func (endpoint *Endpoint) ChanOpenTry() error {
endpoint.IncrementNextChannelSequence()
err := endpoint.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey)
msg := channeltypes.NewMsgChannelOpenTry(
endpoint.ChannelConfig.PortID,
endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID},
endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version,
proof, height,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
res, err := endpoint.Chain.SendMsgs(msg)
if err != nil {
return err
}
if endpoint.ChannelID == "" {
endpoint.ChannelID, err = ParseChannelIDFromEvents(res.Events)
require.NoError(endpoint.Chain.TB, err)
}
// update version to selected app version
// NOTE: this update must be performed after the endpoint channelID is set
endpoint.ChannelConfig.Version = endpoint.GetChannel().Version
endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version
return nil
}
// ChanOpenAck will construct and execute a MsgChannelOpenAck on the associated endpoint.
func (endpoint *Endpoint) ChanOpenAck() error {
err := endpoint.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey)
msg := channeltypes.NewMsgChannelOpenAck(
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version, // testing doesn't use flexible selection
proof, height,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
if err = endpoint.Chain.sendMsgs(msg); err != nil {
return err
}
endpoint.ChannelConfig.Version = endpoint.GetChannel().Version
return nil
}
// ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint.
func (endpoint *Endpoint) ChanOpenConfirm() error {
err := endpoint.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey)
msg := channeltypes.NewMsgChannelOpenConfirm(
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
proof, height,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
return endpoint.Chain.sendMsgs(msg)
}
// ChanCloseInit will construct and execute a MsgChannelCloseInit on the associated endpoint.
//
// NOTE: does not work with ibc-transfer module
func (endpoint *Endpoint) ChanCloseInit() error {
msg := channeltypes.NewMsgChannelCloseInit(
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
endpoint.Chain.SenderAccount.GetAddress().String(),
)
return endpoint.Chain.sendMsgs(msg)
}
// SendPacket sends a packet through the channel keeper using the associated endpoint
// The counterparty client is updated so proofs can be sent to the counterparty chain.
// The packet sequence generated for the packet to be sent is returned. An error
// is returned if one occurs.
func (endpoint *Endpoint) SendPacket(
timeoutHeight clienttypes.Height,
timeoutTimestamp uint64,
data []byte,
) (uint64, error) {
// no need to send message, acting as a module
sequence, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, timeoutHeight, timeoutTimestamp, data)
if err != nil {
return 0, err
}
// commit changes since no message was sent
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
err = endpoint.Counterparty.UpdateClient()
if err != nil {
return 0, err
}
return sequence, nil
}
// RecvPacket receives a packet on the associated endpoint.
// The counterparty client is updated.
func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error {
_, err := endpoint.RecvPacketWithResult(packet)
if err != nil {
return err
}
return nil
}
// RecvPacketWithResult receives a packet on the associated endpoint and the result
// of the transaction is returned. The counterparty client is updated.
func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*abci.ExecTxResult, error) {
// get proof of packet commitment on source
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey)
recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
// receive on counterparty and update source client
res, err := endpoint.Chain.SendMsgs(recvMsg)
if err != nil {
return nil, err
}
if err := endpoint.Counterparty.UpdateClient(); err != nil {
return nil, err
}
return res, nil
}
// WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint.
// The counterparty client is updated.
func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error {
// no need to send message, acting as a handler
err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), packet, ack)
if err != nil {
return err
}
// commit changes since no message was sent
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
return endpoint.Counterparty.UpdateClient()
}
// AcknowledgePacket sends a MsgAcknowledgement to the channel associated with the endpoint.
func (endpoint *Endpoint) AcknowledgePacket(packet channeltypes.Packet, ack []byte) error {
// get proof of acknowledgement on counterparty
packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
return endpoint.Chain.sendMsgs(ackMsg)
}
// AcknowledgePacketWithResult sends a MsgAcknowledgement to the channel associated with the endpoint and returns the result.
func (endpoint *Endpoint) AcknowledgePacketWithResult(packet channeltypes.Packet, ack []byte) (*abci.ExecTxResult, error) {
// get proof of acknowledgement on counterparty
packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
return endpoint.Chain.SendMsgs(ackMsg)
}
// TimeoutPacketWithResult sends a MsgTimeout to the channel associated with the endpoint.
func (endpoint *Endpoint) TimeoutPacketWithResult(packet channeltypes.Packet) (*abci.ExecTxResult, error) {
// get proof for timeout based on channel order
var packetKey []byte
switch endpoint.ChannelConfig.Order {
case channeltypes.ORDERED:
packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel())
case channeltypes.UNORDERED:
packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
default:
return nil, fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order)
}
counterparty := endpoint.Counterparty
proof, proofHeight := counterparty.QueryProof(packetKey)
nextSeqRecv, found := counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(counterparty.Chain.GetContext(), counterparty.ChannelConfig.PortID, counterparty.ChannelID)
require.True(endpoint.Chain.TB, found)
timeoutMsg := channeltypes.NewMsgTimeout(
packet, nextSeqRecv,
proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(),
)
return endpoint.Chain.SendMsgs(timeoutMsg)
}
// TimeoutPacket sends a MsgTimeout to the channel associated with the endpoint.
func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error {
_, err := endpoint.TimeoutPacketWithResult(packet)
return err
}
// TimeoutOnClose sends a MsgTimeoutOnClose to the channel associated with the endpoint.
func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error {
// get proof for timeout based on channel order
var packetKey []byte
switch endpoint.ChannelConfig.Order {
case channeltypes.ORDERED:
packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel())
case channeltypes.UNORDERED:
packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
default:
return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order)
}
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel())
closedProof, _ := endpoint.Counterparty.QueryProof(channelKey)
nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
require.True(endpoint.Chain.TB, found)
timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose(
packet, nextSeqRecv,
proof, closedProof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(),
)
return endpoint.Chain.sendMsgs(timeoutOnCloseMsg)
}
// Deprecated: usage of this function should be replaced by `UpdateChannel`
// SetChannelState sets a channel state
func (endpoint *Endpoint) SetChannelState(state channeltypes.State) error {
channel := endpoint.GetChannel()
channel.State = state
endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel)
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
return endpoint.Counterparty.UpdateClient()
}
// UpdateChannel updates the channel associated with the given endpoint. It accepts a
// closure which takes a channel allowing the caller to modify its fields.
func (endpoint *Endpoint) UpdateChannel(updater func(channel *channeltypes.Channel)) {
channel := endpoint.GetChannel()
updater(&channel)
endpoint.SetChannel(channel)
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
err := endpoint.Counterparty.UpdateClient()
require.NoError(endpoint.Chain.TB, err)
}
// GetClientLatestHeight returns the latest height for the client state for this endpoint.
// The client state is expected to exist otherwise testing will fail.
func (endpoint *Endpoint) GetClientLatestHeight() exported.Height {
return endpoint.Chain.GetClientLatestHeight(endpoint.ClientID)
}
// GetClientState retrieves the client state for this endpoint. The
// client state is expected to exist otherwise testing will fail.
func (endpoint *Endpoint) GetClientState() exported.ClientState {
return endpoint.Chain.GetClientState(endpoint.ClientID)
}
// SetClientState sets the client state for this endpoint.
func (endpoint *Endpoint) SetClientState(clientState exported.ClientState) {
endpoint.Chain.App.GetIBCKeeper().ClientKeeper.SetClientState(endpoint.Chain.GetContext(), endpoint.ClientID, clientState)
}
// GetConsensusState retrieves the Consensus State for this endpoint at the provided height.
// The consensus state is expected to exist otherwise testing will fail.
func (endpoint *Endpoint) GetConsensusState(height exported.Height) exported.ConsensusState {
consensusState, found := endpoint.Chain.GetConsensusState(endpoint.ClientID, height)
require.True(endpoint.Chain.TB, found)
return consensusState
}
// SetConsensusState sets the consensus state for this endpoint.
func (endpoint *Endpoint) SetConsensusState(consensusState exported.ConsensusState, height exported.Height) {
endpoint.Chain.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(endpoint.Chain.GetContext(), endpoint.ClientID, height, consensusState)
}
// GetConnection retrieves an IBC Connection for the endpoint. The
// connection is expected to exist otherwise testing will fail.
func (endpoint *Endpoint) GetConnection() connectiontypes.ConnectionEnd {
connection, found := endpoint.Chain.App.GetIBCKeeper().ConnectionKeeper.GetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID)
require.True(endpoint.Chain.TB, found)
return connection
}
// SetConnection sets the connection for this endpoint.
func (endpoint *Endpoint) SetConnection(connection connectiontypes.ConnectionEnd) {
endpoint.Chain.App.GetIBCKeeper().ConnectionKeeper.SetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID, connection)
}
// GetChannel retrieves an IBC Channel for the endpoint. The channel
// is expected to exist otherwise testing will fail.
func (endpoint *Endpoint) GetChannel() channeltypes.Channel {
channel, found := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID)
require.True(endpoint.Chain.TB, found)
return channel
}
// SetChannel sets the channel for this endpoint.
func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) {
endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel)
}
// QueryClientStateProof performs and abci query for a client stat associated
// with this endpoint and returns the ClientState along with the proof.
func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) {
// retrieve client state to provide proof for
clientState := endpoint.GetClientState()
clientKey := host.FullClientStateKey(endpoint.ClientID)
clientProof, _ := endpoint.QueryProof(clientKey)
return clientState, clientProof
}
// UpdateConnection updates the connection associated with the given endpoint. It accepts a
// closure which takes a connection allowing the caller to modify the connection fields.
func (endpoint *Endpoint) UpdateConnection(updater func(connection *connectiontypes.ConnectionEnd)) {
connection := endpoint.GetConnection()
updater(&connection)
endpoint.SetConnection(connection)
}