x/ibc: testing pkg (#6356)
* add ibc testing pkg with testchain * add ibctestsuite * add create connection and channel support * lint fixes * lint * revert * simplify code via lint * change suite to coordinator * Update x/ibc/testing/chain.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * make trust level var and remove get from channel test struct * apply most suggestions from pr review * split conn handshake into single step funcs * split channel handshake into separate funcs * apply @fedekunze suggestions Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
a8298976ac
commit
6851c844b3
405
x/ibc/testing/chain.go
Normal file
405
x/ibc/testing/chain.go
Normal file
@ -0,0 +1,405 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
tmmath "github.com/tendermint/tendermint/libs/math"
|
||||
lite "github.com/tendermint/tendermint/lite2"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
|
||||
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/keeper"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default params used to create a TM client
|
||||
TrustingPeriod time.Duration = time.Hour * 24 * 7 * 2
|
||||
UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3
|
||||
MaxClockDrift time.Duration = time.Second * 10
|
||||
|
||||
ConnectionVersion = "1.0"
|
||||
ChannelVersion = "1.0"
|
||||
|
||||
ClientIDPrefix = "clientFor"
|
||||
ConnectionIDPrefix = "connectionid"
|
||||
ChannelIDPrefix = "channelid"
|
||||
PortIDPrefix = "portid"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultTrustLevel tmmath.Fraction = lite.DefaultTrustLevel
|
||||
)
|
||||
|
||||
// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI
|
||||
// header and the validators of the TestChain. It also contains a field called ChainID. This
|
||||
// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount
|
||||
// is used for delivering transactions through the application state.
|
||||
// NOTE: the actual application uses an empty chain-id for ease of testing.
|
||||
type TestChain struct {
|
||||
t *testing.T
|
||||
|
||||
App *simapp.SimApp
|
||||
ChainID string
|
||||
LastHeader ibctmtypes.Header // header for last block height committed
|
||||
CurrentHeader abci.Header // header for current block height
|
||||
Querier sdk.Querier
|
||||
|
||||
Vals *tmtypes.ValidatorSet
|
||||
Signers []tmtypes.PrivValidator
|
||||
|
||||
senderPrivKey crypto.PrivKey
|
||||
SenderAccount authtypes.AccountI
|
||||
|
||||
// IBC specific helpers
|
||||
ClientIDs []string // ClientID's used on this chain
|
||||
Connections []TestConnection // track connectionID's created for this chain
|
||||
Channels []TestChannel // track portID/channelID's created for this chain
|
||||
}
|
||||
|
||||
// NewTestChain initializes a new TestChain instance with a single validator set using a
|
||||
// generated private key. It also creates a sender account to be used for delivering transactions.
|
||||
//
|
||||
// The first block height is committed to state in order to allow for client creations on
|
||||
// counterparty chains. The TestChain will return with a block height starting at 2.
|
||||
//
|
||||
// Time management is handled by the Coordinator in order to ensure synchrony between chains.
|
||||
// Each update of any chain increments the block header time for all chains by 5 seconds.
|
||||
func NewTestChain(t *testing.T, chainID string) *TestChain {
|
||||
// generate validator private/public key
|
||||
privVal := tmtypes.NewMockPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
// create validator set with single validator
|
||||
validator := tmtypes.NewValidator(pubKey, 1)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||
signers := []tmtypes.PrivValidator{privVal}
|
||||
|
||||
app := simapp.Setup(false)
|
||||
ctx := app.BaseApp.NewContext(false,
|
||||
abci.Header{
|
||||
Height: 1,
|
||||
Time: globalStartTime,
|
||||
},
|
||||
)
|
||||
|
||||
// generate and set SenderAccount
|
||||
senderPrivKey := secp256k1.GenPrivKey()
|
||||
simapp.AddTestAddrsFromPubKeys(app, ctx, []crypto.PubKey{senderPrivKey.PubKey()}, sdk.NewInt(10000000000))
|
||||
acc := app.AccountKeeper.GetAccount(ctx, sdk.AccAddress(senderPrivKey.PubKey().Address()))
|
||||
|
||||
// commit init chain changes so create client can be called by a counterparty chain
|
||||
app.Commit()
|
||||
// create current header and call begin block
|
||||
header := abci.Header{
|
||||
Height: 2,
|
||||
Time: globalStartTime.Add(timeIncrement),
|
||||
}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
lastHeader := ibctmtypes.CreateTestHeader(chainID, 1, globalStartTime, valSet, signers)
|
||||
|
||||
// create an account to send transactions from
|
||||
return &TestChain{
|
||||
t: t,
|
||||
ChainID: chainID,
|
||||
App: app,
|
||||
LastHeader: lastHeader,
|
||||
CurrentHeader: header,
|
||||
Querier: keeper.NewQuerier(*app.IBCKeeper),
|
||||
Vals: valSet,
|
||||
Signers: signers,
|
||||
senderPrivKey: senderPrivKey,
|
||||
SenderAccount: acc,
|
||||
}
|
||||
}
|
||||
|
||||
// GetContext returns the current context for the application.
|
||||
func (chain *TestChain) GetContext() sdk.Context {
|
||||
return chain.App.BaseApp.NewContext(false, chain.CurrentHeader)
|
||||
}
|
||||
|
||||
// QueryProof performs an abci query with the given key and returns the merkle proof for the query
|
||||
// and the height at which the query was performed.
|
||||
func (chain *TestChain) QueryProof(key []byte) (commitmenttypes.MerkleProof, uint64) {
|
||||
res := chain.App.Query(abci.RequestQuery{
|
||||
Path: fmt.Sprintf("store/%s/key", host.StoreKey),
|
||||
Height: chain.App.LastBlockHeight(),
|
||||
Data: key,
|
||||
Prove: true,
|
||||
})
|
||||
|
||||
proof := commitmenttypes.MerkleProof{
|
||||
Proof: res.Proof,
|
||||
}
|
||||
|
||||
return proof, uint64(res.Height)
|
||||
}
|
||||
|
||||
// NextBlock sets the last header to the current header and increments the current header to be
|
||||
// at the next block height. It does not update the time as that is handled by the Coordinator.
|
||||
//
|
||||
// CONTRACT: this function must only be called after app.Commit() occurs
|
||||
func (chain *TestChain) NextBlock() {
|
||||
// set the last header to the current header
|
||||
chain.LastHeader = ibctmtypes.CreateTestHeader(
|
||||
chain.CurrentHeader.ChainID,
|
||||
chain.CurrentHeader.Height,
|
||||
chain.CurrentHeader.Time,
|
||||
chain.Vals, chain.Signers,
|
||||
)
|
||||
|
||||
// increment the current header
|
||||
chain.CurrentHeader = abci.Header{
|
||||
Height: chain.CurrentHeader.Height + 1,
|
||||
Time: chain.CurrentHeader.Time,
|
||||
}
|
||||
}
|
||||
|
||||
// SendMsg delivers a transaction through the application. It updates the senders sequence
|
||||
// number and updates the TestChain's headers.
|
||||
func (chain *TestChain) SendMsg(msg sdk.Msg) error {
|
||||
_, _, err := simapp.SignCheckDeliver(
|
||||
chain.t,
|
||||
chain.App.Codec(),
|
||||
chain.App.BaseApp,
|
||||
chain.GetContext().BlockHeader(),
|
||||
[]sdk.Msg{msg},
|
||||
[]uint64{chain.SenderAccount.GetAccountNumber()},
|
||||
[]uint64{chain.SenderAccount.GetSequence()},
|
||||
true, true, chain.senderPrivKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// SignCheckDeliver calls app.Commit()
|
||||
chain.NextBlock()
|
||||
|
||||
// increment sequence for successful transaction execution
|
||||
chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClientID appends a new clientID string in the format:
|
||||
// ClientFor<counterparty-chain-id><index>
|
||||
func (chain *TestChain) NewClientID(counterpartyChainID string) string {
|
||||
clientID := ClientIDPrefix + counterpartyChainID + string(len(chain.ClientIDs))
|
||||
|
||||
chain.ClientIDs = append(chain.ClientIDs, clientID)
|
||||
return clientID
|
||||
}
|
||||
|
||||
// NewConnection appends a new TestConnection which contains references to the connection id,
|
||||
// client id and counterparty client id. The connection id format:
|
||||
// connectionid<index>
|
||||
func (chain *TestChain) NewTestConnection(clientID, counterpartyClientID string) TestConnection {
|
||||
connectionID := ConnectionIDPrefix + string(len(chain.Connections))
|
||||
conn := TestConnection{
|
||||
ID: connectionID,
|
||||
ClientID: clientID,
|
||||
CounterpartyClientID: counterpartyClientID,
|
||||
}
|
||||
|
||||
chain.Connections = append(chain.Connections, conn)
|
||||
return conn
|
||||
}
|
||||
|
||||
// NewTestChannel appends a new TestChannel which contains references to the port and channel ID
|
||||
// used for channel creation and interaction. The channel id and port id format:
|
||||
// channelid<index>
|
||||
// portid<index>
|
||||
func (chain *TestChain) NewTestChannel() TestChannel {
|
||||
portID := PortIDPrefix + string(len(chain.Channels))
|
||||
channelID := ChannelIDPrefix + string(len(chain.Channels))
|
||||
channel := TestChannel{
|
||||
PortID: portID,
|
||||
ChannelID: channelID,
|
||||
}
|
||||
|
||||
chain.Channels = append(chain.Channels, channel)
|
||||
|
||||
return channel
|
||||
}
|
||||
|
||||
// CreateTMClient will construct and execute a 07-tendermint MsgCreateClient. A counterparty
|
||||
// client will be created on the (target) chain.
|
||||
func (chain *TestChain) CreateTMClient(counterparty *TestChain, clientID string) error {
|
||||
// construct MsgCreateClient using counterparty
|
||||
msg := ibctmtypes.NewMsgCreateClient(
|
||||
clientID, counterparty.LastHeader,
|
||||
DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// UpdateTMClient will construct and execute a 07-tendermint MsgUpdateClient. The counterparty
|
||||
// client will be updated on the (target) chain.
|
||||
func (chain *TestChain) UpdateTMClient(counterparty *TestChain, clientID string) error {
|
||||
msg := ibctmtypes.NewMsgUpdateClient(
|
||||
clientID, counterparty.LastHeader,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ConnectionOpenInit will construct and execute a MsgConnectionOpenInit.
|
||||
func (chain *TestChain) ConnectionOpenInit(
|
||||
counterparty *TestChain,
|
||||
connection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
prefix := commitmenttypes.NewMerklePrefix(counterparty.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix().Bytes())
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenInit(
|
||||
connection.ID, connection.ClientID,
|
||||
counterpartyConnection.ID, connection.CounterpartyClientID,
|
||||
prefix,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ConnectionOpenTry will construct and execute a MsgConnectionOpenTry.
|
||||
func (chain *TestChain) ConnectionOpenTry(
|
||||
counterparty *TestChain,
|
||||
connection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
prefix := commitmenttypes.NewMerklePrefix(counterparty.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix().Bytes())
|
||||
|
||||
connectionKey := host.KeyConnection(counterpartyConnection.ID)
|
||||
proofInit, proofHeight := counterparty.QueryProof(connectionKey)
|
||||
|
||||
consensusHeight := uint64(counterparty.App.LastBlockHeight())
|
||||
consensusKey := prefixedClientKey(connection.ClientID, host.KeyConsensusState(consensusHeight))
|
||||
proofConsensus, _ := counterparty.QueryProof(consensusKey)
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenTry(
|
||||
connection.ID, connection.ClientID,
|
||||
counterpartyConnection.ID, connection.CounterpartyClientID,
|
||||
prefix, []string{ConnectionVersion},
|
||||
proofInit, proofConsensus,
|
||||
proofHeight, consensusHeight,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ConnectionOpenAck will construct and execute a MsgConnectionOpenAck.
|
||||
func (chain *TestChain) ConnectionOpenAck(
|
||||
counterparty *TestChain,
|
||||
connection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
connectionKey := host.KeyConnection(counterpartyConnection.ID)
|
||||
proofTry, proofHeight := counterparty.QueryProof(connectionKey)
|
||||
|
||||
consensusHeight := uint64(counterparty.App.LastBlockHeight())
|
||||
consensusKey := prefixedClientKey(connection.ClientID, host.KeyConsensusState(consensusHeight))
|
||||
proofConsensus, _ := counterparty.QueryProof(consensusKey)
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenAck(
|
||||
connection.ID,
|
||||
proofTry, proofConsensus,
|
||||
proofHeight, consensusHeight,
|
||||
ConnectionVersion,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ConnectionOpenConfirm will construct and execute a MsgConnectionOpenConfirm.
|
||||
func (chain *TestChain) ConnectionOpenConfirm(
|
||||
counterparty *TestChain,
|
||||
connection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
connectionKey := host.KeyConnection(counterpartyConnection.ID)
|
||||
proof, height := counterparty.QueryProof(connectionKey)
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenConfirm(
|
||||
connection.ID,
|
||||
proof, height,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ChannelOpenInit will construct and execute a MsgChannelOpenInit.
|
||||
func (chain *TestChain) ChannelOpenInit(
|
||||
ch, counterparty TestChannel,
|
||||
order channeltypes.Order,
|
||||
connectionID string,
|
||||
) error {
|
||||
msg := channeltypes.NewMsgChannelOpenInit(
|
||||
ch.PortID, ch.ChannelID,
|
||||
ChannelVersion, order, []string{connectionID},
|
||||
counterparty.PortID, counterparty.ChannelID,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ChannelOpenTry will construct and execute a MsgChannelOpenTry.
|
||||
func (chain *TestChain) ChannelOpenTry(
|
||||
ch, counterparty TestChannel,
|
||||
order channeltypes.Order,
|
||||
connectionID string,
|
||||
) error {
|
||||
proof, height := chain.QueryProof(host.KeyConnection(connectionID))
|
||||
|
||||
msg := channeltypes.NewMsgChannelOpenTry(
|
||||
ch.PortID, ch.ChannelID,
|
||||
ChannelVersion, order, []string{connectionID},
|
||||
counterparty.PortID, counterparty.ChannelID,
|
||||
ChannelVersion,
|
||||
proof, height,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ChannelOpenAck will construct and execute a MsgChannelOpenAck.
|
||||
func (chain *TestChain) ChannelOpenAck(
|
||||
ch, counterparty TestChannel,
|
||||
connectionID string,
|
||||
) error {
|
||||
proof, height := chain.QueryProof(host.KeyConnection(connectionID))
|
||||
|
||||
msg := channeltypes.NewMsgChannelOpenAck(
|
||||
ch.PortID, ch.ChannelID,
|
||||
ChannelVersion,
|
||||
proof, height,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
|
||||
// ChannelOpenConfirm will construct and execute a MsgChannelOpenConfirm.
|
||||
func (chain *TestChain) ChannelOpenConfirm(
|
||||
ch, counterparty TestChannel,
|
||||
connectionID string,
|
||||
) error {
|
||||
proof, height := chain.QueryProof(host.KeyConnection(connectionID))
|
||||
|
||||
msg := channeltypes.NewMsgChannelOpenConfirm(
|
||||
ch.PortID, ch.ChannelID,
|
||||
proof, height,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
return chain.SendMsg(msg)
|
||||
}
|
||||
411
x/ibc/testing/coordinator.go
Normal file
411
x/ibc/testing/coordinator.go
Normal file
@ -0,0 +1,411 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
|
||||
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
|
||||
)
|
||||
|
||||
var (
|
||||
ChainIDPrefix = "testchain"
|
||||
globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
|
||||
timeIncrement = time.Second * 5
|
||||
)
|
||||
|
||||
// Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains
|
||||
// in sync with regards to time.
|
||||
type Coordinator struct {
|
||||
t *testing.T
|
||||
|
||||
Chains map[string]*TestChain
|
||||
}
|
||||
|
||||
// NewCoordinator initializes Coordinator with N TestChain's
|
||||
func NewCoordinator(t *testing.T, n int) *Coordinator {
|
||||
chains := make(map[string]*TestChain)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
chainID := ChainIDPrefix + string(i)
|
||||
chains[chainID] = NewTestChain(t, chainID)
|
||||
}
|
||||
return &Coordinator{
|
||||
t: t,
|
||||
Chains: chains,
|
||||
}
|
||||
}
|
||||
|
||||
// IncrementTime iterates through all the TestChain's and increments their current header time
|
||||
// by 5 seconds.
|
||||
//
|
||||
// CONTRACT: this function must be called after every commit on any TestChain.
|
||||
func (coord *Coordinator) IncrementTime() {
|
||||
for _, chain := range coord.Chains {
|
||||
chain.CurrentHeader = abci.Header{
|
||||
Height: chain.CurrentHeader.Height,
|
||||
Time: chain.CurrentHeader.Time.Add((timeIncrement)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetChain returns the TestChain using the given chainID and returns an error if it does
|
||||
// not exist.
|
||||
func (coord *Coordinator) GetChain(chainID string) *TestChain {
|
||||
chain, found := coord.Chains[chainID]
|
||||
require.True(coord.t, found, fmt.Sprintf("%s chain does not exist", chainID))
|
||||
return chain
|
||||
}
|
||||
|
||||
// CommitBlock commits a block on the provided indexes and then increments the global time.
|
||||
//
|
||||
// CONTRACT: the passed in list of indexes must not contain duplicates
|
||||
func (coord *Coordinator) CommitBlock(chains ...string) {
|
||||
for _, chainID := range chains {
|
||||
chain := coord.GetChain(chainID)
|
||||
chain.App.Commit()
|
||||
chain.NextBlock()
|
||||
}
|
||||
coord.IncrementTime()
|
||||
}
|
||||
|
||||
// CommitNBlocks commits n blocks to state and updates the block height by 1 for each commit.
|
||||
func (coord *Coordinator) CommitNBlocks(chainID string, n uint64) {
|
||||
chain := coord.GetChain(chainID)
|
||||
|
||||
for i := uint64(0); i < n; i++ {
|
||||
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
|
||||
chain.App.Commit()
|
||||
chain.NextBlock()
|
||||
coord.IncrementTime()
|
||||
}
|
||||
}
|
||||
|
||||
// CreateClient creates a counterparty client on the source chain and returns the clientID.
|
||||
func (coord *Coordinator) CreateClient(
|
||||
sourceID, counterpartyID string,
|
||||
clientType clientexported.ClientType,
|
||||
) (clientID string, err error) {
|
||||
coord.CommitBlock(sourceID, counterpartyID)
|
||||
|
||||
source := coord.GetChain(sourceID)
|
||||
counterparty := coord.GetChain(counterpartyID)
|
||||
|
||||
clientID = source.NewClientID(counterparty.ChainID)
|
||||
|
||||
switch clientType {
|
||||
case clientexported.Tendermint:
|
||||
err = source.CreateTMClient(counterparty, clientID)
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("client type %s is not supported", clientType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
coord.IncrementTime()
|
||||
|
||||
return clientID, nil
|
||||
}
|
||||
|
||||
// UpdateClient updates a counterparty client on the source chain.
|
||||
func (coord *Coordinator) UpdateClient(
|
||||
sourceID, counterpartyID,
|
||||
clientID string,
|
||||
clientType clientexported.ClientType,
|
||||
) (err error) {
|
||||
coord.CommitBlock(sourceID, counterpartyID)
|
||||
|
||||
source := coord.GetChain(sourceID)
|
||||
counterparty := coord.GetChain(counterpartyID)
|
||||
|
||||
switch clientType {
|
||||
case clientexported.Tendermint:
|
||||
err = source.UpdateTMClient(counterparty, clientID)
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("client type %s is not supported", clientType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
coord.IncrementTime()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateConnection constructs and executes connection handshake messages in order to create
|
||||
// OPEN channels on source and counterparty chains. The connection information of the source
|
||||
// and counterparty's are returned within a TestConnection struct. If there is a fault in
|
||||
// the connection handshake then an error is returned.
|
||||
//
|
||||
// NOTE: The counterparty testing connection will be created even if it is not created in the
|
||||
// application state.
|
||||
func (coord *Coordinator) CreateConnection(
|
||||
sourceID, counterpartyID,
|
||||
clientID, counterpartyClientID string,
|
||||
state connectiontypes.State,
|
||||
) (TestConnection, TestConnection, error) {
|
||||
source := coord.GetChain(sourceID)
|
||||
counterparty := coord.GetChain(counterpartyID)
|
||||
|
||||
sourceConnection := source.NewTestConnection(clientID, counterpartyClientID)
|
||||
counterpartyConnection := counterparty.NewTestConnection(counterpartyClientID, clientID)
|
||||
|
||||
if err := coord.CreateConnectionInit(source, counterparty, sourceConnection, counterpartyConnection); err != nil {
|
||||
return sourceConnection, counterpartyConnection, err
|
||||
}
|
||||
|
||||
if err := coord.CreateConnectionOpenTry(counterparty, source, counterpartyConnection, sourceConnection); err != nil {
|
||||
return sourceConnection, counterpartyConnection, err
|
||||
}
|
||||
|
||||
if err := coord.CreateConnectionOpenAck(source, counterparty, sourceConnection, counterpartyConnection); err != nil {
|
||||
return sourceConnection, counterpartyConnection, err
|
||||
}
|
||||
|
||||
if err := coord.CreateConnectionOpenConfirm(counterparty, source, counterpartyConnection, sourceConnection); err != nil {
|
||||
return sourceConnection, counterpartyConnection, err
|
||||
}
|
||||
|
||||
return sourceConnection, counterpartyConnection, nil
|
||||
}
|
||||
|
||||
// CreateConenctionInit initializes a connection on the source chain with the state INIT
|
||||
// using the OpenInit handshake call.
|
||||
func (coord *Coordinator) CreateConnectionInit(
|
||||
source, counterparty *TestChain,
|
||||
sourceConnection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
// initialize connection on source
|
||||
if err := source.ConnectionOpenInit(counterparty, sourceConnection, counterpartyConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
counterpartyConnection.ClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateConenctionOpenTry initializes a connection on the source chain with the state TRYOPEN
|
||||
// using the OpenTry handshake call.
|
||||
func (coord *Coordinator) CreateConnectionOpenTry(
|
||||
source, counterparty *TestChain,
|
||||
sourceConnection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
// initialize TRYOPEN connection on source
|
||||
if err := source.ConnectionOpenTry(counterparty, sourceConnection, counterpartyConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
counterpartyConnection.ClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateConnectionOpenAck initializes a connection on the source chain with the state OPEN
|
||||
// using the OpenAck handshake call.
|
||||
func (coord *Coordinator) CreateConnectionOpenAck(
|
||||
source, counterparty *TestChain,
|
||||
sourceConnection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
// set OPEN connection on source using OpenAck
|
||||
if err := source.ConnectionOpenAck(counterparty, sourceConnection, counterpartyConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
counterpartyConnection.ClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateConnectionOpenConfirm initializes a connection on the source chain with the state OPEN
|
||||
// using the OpenConfirm handshake call.
|
||||
func (coord *Coordinator) CreateConnectionOpenConfirm(
|
||||
source, counterparty *TestChain,
|
||||
sourceConnection, counterpartyConnection TestConnection,
|
||||
) error {
|
||||
if err := counterparty.ConnectionOpenConfirm(counterparty, sourceConnection, counterpartyConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
source.ChainID, counterparty.ChainID,
|
||||
sourceConnection.ClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateChannel constructs and executes channel handshake messages in order to create
|
||||
// channels on source and counterparty chains with the passed in Channel State. The portID and
|
||||
// channelID of source and counterparty are returned.
|
||||
//
|
||||
// NOTE: The counterparty testing channel will be created even if it is not created in the
|
||||
// application state.
|
||||
func (coord *Coordinator) CreateChannel(
|
||||
sourceID, counterpartyID string,
|
||||
connection, counterpartyConnection TestConnection,
|
||||
order channeltypes.Order,
|
||||
state channeltypes.State,
|
||||
) (TestChannel, TestChannel, error) {
|
||||
source := coord.GetChain(sourceID)
|
||||
counterparty := coord.GetChain(counterpartyID)
|
||||
|
||||
sourceChannel := source.NewTestChannel()
|
||||
counterpartyChannel := counterparty.NewTestChannel()
|
||||
|
||||
if err := coord.CreateChannelInit(source, counterparty, sourceChannel, counterpartyChannel, connection, order); err != nil {
|
||||
return sourceChannel, counterpartyChannel, err
|
||||
}
|
||||
|
||||
if err := coord.CreateChannelOpenTry(counterparty, source, counterpartyChannel, sourceChannel, counterpartyConnection, order); err != nil {
|
||||
return sourceChannel, counterpartyChannel, err
|
||||
}
|
||||
|
||||
if err := coord.CreateChannelOpenAck(source, counterparty, sourceChannel, counterpartyChannel, connection); err != nil {
|
||||
return sourceChannel, counterpartyChannel, err
|
||||
}
|
||||
|
||||
if err := coord.CreateChannelOpenConfirm(counterparty, source, counterpartyChannel, sourceChannel, counterpartyConnection); err != nil {
|
||||
return sourceChannel, counterpartyChannel, err
|
||||
}
|
||||
|
||||
return sourceChannel, counterpartyChannel, nil
|
||||
}
|
||||
|
||||
// CreateChannelInit initializes a channel on the source chain with the state INIT
|
||||
// using the OpenInit handshake call.
|
||||
func (coord *Coordinator) CreateChannelInit(
|
||||
source, counterparty *TestChain,
|
||||
sourceChannel, counterpartyChannel TestChannel,
|
||||
connection TestConnection,
|
||||
order channeltypes.Order,
|
||||
) error {
|
||||
|
||||
// initialize channel on source
|
||||
if err := source.ChannelOpenInit(sourceChannel, counterpartyChannel, order, connection.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
connection.CounterpartyClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateChannelOpenTry initializes a channel on the source chain with the state TRYOPEN
|
||||
// using the OpenTry handshake call.
|
||||
func (coord *Coordinator) CreateChannelOpenTry(
|
||||
source, counterparty *TestChain,
|
||||
sourceChannel, counterpartyChannel TestChannel,
|
||||
connection TestConnection,
|
||||
order channeltypes.Order,
|
||||
) error {
|
||||
|
||||
// initialize channel on source
|
||||
if err := source.ChannelOpenTry(sourceChannel, counterpartyChannel, order, connection.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
connection.CounterpartyClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateChannelOpenAck initializes a channel on the source chain with the state OPEN
|
||||
// using the OpenAck handshake call.
|
||||
func (coord *Coordinator) CreateChannelOpenAck(
|
||||
source, counterparty *TestChain,
|
||||
sourceChannel, counterpartyChannel TestChannel,
|
||||
connection TestConnection,
|
||||
) error {
|
||||
|
||||
// initialize channel on source
|
||||
if err := source.ChannelOpenAck(sourceChannel, counterpartyChannel, connection.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
connection.CounterpartyClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateChannelOpenConfirm initializes a channel on the source chain with the state OPEN
|
||||
// using the OpenConfirm handshake call.
|
||||
func (coord *Coordinator) CreateChannelOpenConfirm(
|
||||
source, counterparty *TestChain,
|
||||
sourceChannel, counterpartyChannel TestChannel,
|
||||
connection TestConnection,
|
||||
) error {
|
||||
|
||||
// initialize channel on source
|
||||
if err := source.ChannelOpenConfirm(sourceChannel, counterpartyChannel, connection.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
coord.IncrementTime()
|
||||
|
||||
// update source client on counterparty connection
|
||||
if err := coord.UpdateClient(
|
||||
counterparty.ChainID, source.ChainID,
|
||||
connection.CounterpartyClientID, clientexported.Tendermint,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
5
x/ibc/testing/keys.go
Normal file
5
x/ibc/testing/keys.go
Normal file
@ -0,0 +1,5 @@
|
||||
package testing
|
||||
|
||||
func prefixedClientKey(clientID string, key []byte) []byte {
|
||||
return append([]byte("clients/"+clientID+"/"), key...)
|
||||
}
|
||||
16
x/ibc/testing/types.go
Normal file
16
x/ibc/testing/types.go
Normal file
@ -0,0 +1,16 @@
|
||||
package testing
|
||||
|
||||
// TestConnections is a testing helper struct to keep track of the connectionID, source clientID,
|
||||
// and counterparty clientID used in creating and interacting with a connection.
|
||||
type TestConnection struct {
|
||||
ID string
|
||||
ClientID string
|
||||
CounterpartyClientID string
|
||||
}
|
||||
|
||||
// TestChannel is a testing helper struct to keep track of the portID and channelID
|
||||
// used in creating and interacting with a channel.
|
||||
type TestChannel struct {
|
||||
PortID string
|
||||
ChannelID string
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user