func (endpoint *Endpoint) WriteAcknowledgement(acknowledgement []byte, packet exported.PacketI) error {
	err := endpoint.Chain.App.TIBCKeeper.PacketKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), packet, acknowledgement)
	if err != nil {
		return err
	}
	endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
	return endpoint.Counterparty.UpdateClient()
}
WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint.
The counterparty client is updated.
package tibctesting
import (
	"fmt"
	"github.com/stretchr/testify/require"
	abci "github.com/tendermint/tendermint/abci/types"
	sdk "github.com/cosmos/cosmos-sdk/types"
	clienttypes "github.com/bianjieai/tibc-go/modules/tibc/core/02-client/types"
	packettypes "github.com/bianjieai/tibc-go/modules/tibc/core/04-packet/types"
	commitmenttypes "github.com/bianjieai/tibc-go/modules/tibc/core/23-commitment/types"
	host "github.com/bianjieai/tibc-go/modules/tibc/core/24-host"
	"github.com/bianjieai/tibc-go/modules/tibc/core/exported"
	ibctmtypes "github.com/bianjieai/tibc-go/modules/tibc/light-clients/07-tendermint/types"
)
type Endpoint struct {
	Chain        *TestChain
	Counterparty *Endpoint
	ChainName    string
	ClientConfig ClientConfig
}
func NewEndpoint(chain *TestChain, clientConfig ClientConfig) *Endpoint {
	return &Endpoint{
		Chain:        chain,
		ClientConfig: clientConfig,
	}
}
func NewDefaultEndpoint(chain *TestChain) *Endpoint {
	return &Endpoint{
		Chain:        chain,
		ChainName:    chain.ChainID,
		ClientConfig: NewTendermintConfig(),
	}
}
func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) {
	clientState := endpoint.Counterparty.Chain.GetClientState(endpoint.ChainName)
	return endpoint.QueryProofAtHeight(key, clientState.GetLatestHeight().GetRevisionHeight())
}
func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) {
	return endpoint.Chain.QueryProofAtHeight(key, int64(height))
}
func (endpoint *Endpoint) CreateClient() error {
	endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain)
	endpoint.Chain.Coordinator.UpdateTimeForChain(endpoint.Chain)
	if endpoint.ClientConfig.GetClientType() != exported.Tendermint {
		return fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType())
	}
	tmConfig, ok := endpoint.ClientConfig.(*TendermintConfig)
	require.True(endpoint.Chain.t, ok)
	height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height)
	clientState := ibctmtypes.NewClientState(
		endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel,
		tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift,
		height, commitmenttypes.GetSDKSpecs(), Prefix, 0,
	)
	consensusState := endpoint.Counterparty.Chain.LastHeader.ConsensusState()
	ctx := endpoint.Chain.GetContext()
	endpoint.Chain.App.TIBCKeeper.ClientKeeper.SetChainName(ctx, endpoint.ChainName)
	endpoint.Chain.App.TIBCKeeper.PacketKeeper.SetNextSequenceSend(ctx, endpoint.ChainName, endpoint.Counterparty.ChainName, 1)
	relayers := []string{endpoint.Chain.SenderAccount.GetAddress().String()}
	endpoint.Chain.App.TIBCKeeper.ClientKeeper.RegisterRelayers(endpoint.Chain.GetContext(), endpoint.Counterparty.ChainName, relayers)
	err := endpoint.Chain.App.TIBCKeeper.ClientKeeper.CreateClient(
		endpoint.Chain.GetContext(),
		endpoint.Counterparty.ChainName,
		clientState,
		consensusState,
	)
	require.NoError(endpoint.Chain.t, err)
	endpoint.Chain.App.EndBlock(abci.RequestEndBlock{})
	endpoint.Chain.App.Commit()
	endpoint.Chain.NextBlock()
	endpoint.Chain.Coordinator.IncrementTime()
	return nil
}
func (endpoint *Endpoint) UpdateClient() error {
	endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain)
	if endpoint.ClientConfig.GetClientType() != exported.Tendermint {
		return fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType())
	}
	header, err := endpoint.Chain.ConstructUpdateTMClientHeader(endpoint.Counterparty.Chain, endpoint.Counterparty.ChainName)
	if err != nil {
		return err
	}
	msg, err := clienttypes.NewMsgUpdateClient(
		endpoint.Counterparty.ChainName, header,
		endpoint.Chain.SenderAccount.GetAddress(),
	)
	require.NoError(endpoint.Chain.t, err)
	return endpoint.Chain.sendMsgs(msg)
}
func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error {
	if err := endpoint.Chain.App.TIBCKeeper.PacketKeeper.SendPacket(endpoint.Chain.GetContext(), packet); err != nil {
		return err
	}
	endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
	return endpoint.Counterparty.UpdateClient()
}
func (endpoint *Endpoint) RecvPacket(packet packettypes.Packet) error {
	packetKey := host.PacketCommitmentKey(packet.GetSourceChain(), packet.GetDestChain(), packet.GetSequence())
	proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey)
	recvMsg := packettypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress())
	if err := endpoint.Chain.sendMsgs(recvMsg); err != nil {
		return err
	}
	return endpoint.Counterparty.UpdateClient()
}