Refactor 04-channel/keeper tests to ibc testing pkg (#6400)

* update testing pkg and first keeper test

* fix version bug

* add more helper testing funcs

* move create header to testing pkg

* fix connection state bug

* add staking genesis state

* update simapp with setting validator helper func

* update simapp with valset helper

* fix app hash issue

* update to query from correct iavl proof height

* first keeper test passing

* second test passing 🎉

* fix build

* update tests in all keeper_test

* fix lint

* begin refactoring querier test

* update first querier test and update testing helpers

* finish updating rest of querier tests

* rename ChannelID in TestChannel to ID

* remove usage of chain id for calling helper funcs

* update openinit and opentry tests

* finish opening channel handshake tests

* finish handshake tests

* general testing pkg cleanup

* finish packetsend refactor

* update recvpacket

* packet executed refactored

* finish packet test 🎉

* all tests passing

* cleanup and increase code cov

* remove todos in favor of opened issue #6509

* bump invalid id to meet validation requirements

* bubble up proof height + 1

* Apply suggestions from code review

Co-authored-by: Aditya <adityasripal@gmail.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* fix uninit conn test

* fix compile and address various pr review issues

* Update x/ibc/04-channel/keeper/handshake_test.go

Co-authored-by: Aditya <adityasripal@gmail.com>

* Update x/ibc/04-channel/keeper/handshake_test.go

Co-authored-by: Aditya <adityasripal@gmail.com>

* address @AdityaSripal comments and increase cov

Co-authored-by: Aditya <adityasripal@gmail.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
colin axner 2020-06-26 18:36:04 +02:00 committed by GitHub
parent 9bf3ff75f5
commit 43837b16e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 2536 additions and 1936 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
@ -21,6 +22,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// DefaultConsensusParams defines the default Tendermint consensus params used in
@ -67,6 +69,77 @@ func Setup(isCheckTx bool) *SimApp {
return app
}
// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit (10^6) in the default token of the simapp from first genesis
// account. A Nop logger is set in SimApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
db := dbm.NewMemDB()
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5)
genesisState := NewDefaultGenesisState()
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.Codec().MustMarshalJSON(authGenesis)
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
bondAmt := sdk.NewInt(1000000)
for _, val := range valSet.Validators {
validator := stakingtypes.Validator{
OperatorAddress: val.Address.Bytes(),
ConsensusPubkey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, val.PubKey),
Jailed: false,
Status: sdk.Bonded,
Tokens: bondAmt,
DelegatorShares: sdk.OneDec(),
Description: stakingtypes.Description{},
UnbondingHeight: int64(0),
UnbondingTime: time.Unix(0, 0).UTC(),
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
MinSelfDelegation: sdk.ZeroInt(),
}
validators = append(validators, validator)
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
}
// set validators and delegations
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
genesisState[stakingtypes.ModuleName] = app.Codec().MustMarshalJSON(stakingGenesis)
totalSupply := sdk.NewCoins()
for _, b := range balances {
// add genesis acc tokens and delegated tokens to total supply
totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...)
}
// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().SendEnabled, balances, totalSupply)
genesisState[banktypes.ModuleName] = app.Codec().MustMarshalJSON(bankGenesis)
stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState)
require.NoError(t, err)
// init chain will set the validator set and initialize the genesis accounts
app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
// commit genesis changes
app.Commit()
app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
return app
}
// SetupWithGenesisAccounts initializes a new SimApp with the provided genesis
// accounts and possible balances.
func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {

File diff suppressed because it is too large Load Diff

View File

@ -1,234 +1,250 @@
package keeper_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
lite "github.com/tendermint/tendermint/lite2"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"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"
ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// define constants used for testing
const (
testClientIDA = "testclientida"
testConnectionIDA = "connectionidatob"
testClientIDB = "testclientidb"
testConnectionIDB = "connectionidbtoa"
testPort1 = "firstport"
testPort2 = "secondport"
testPort3 = "thirdport"
testChannel1 = "firstchannel"
testChannel2 = "secondchannel"
testChannel3 = "thirdchannel"
testChannelOrder = types.ORDERED
testChannelVersion = "1.0"
trustingPeriod time.Duration = time.Hour * 24 * 7 * 2
ubdPeriod time.Duration = time.Hour * 24 * 7 * 3
maxClockDrift time.Duration = time.Second * 10
timeoutHeight = 100
timeoutTimestamp = 100
disabledTimeoutTimestamp = 0
disabledTimeoutHeight = 0
)
var (
testPacketCommitment = []byte("packet commitment")
testAcknowledgement = []byte("acknowledgement")
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
// KeeperTestSuite is a testing suite to test keeper functions.
type KeeperTestSuite struct {
suite.Suite
cdc *codec.Codec
querier sdk.Querier
coordinator *ibctesting.Coordinator
chainA *TestChain
chainB *TestChain
// testing chains used for convience and readability
chainA *ibctesting.TestChain
chainB *ibctesting.TestChain
}
// TestKeeperTestSuite runs all the tests within this package.
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
// SetupTest creates a coordinator with 2 test chains.
func (suite *KeeperTestSuite) SetupTest() {
suite.chainA = NewTestChain(testClientIDA)
suite.chainB = NewTestChain(testClientIDB)
suite.cdc = suite.chainA.App.Codec()
suite.querier = ibckeeper.NewQuerier(*suite.chainA.App.IBCKeeper)
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
}
// TestSetChannel create clients and connections on both chains. It tests for the non-existence
// and existence of a channel in INIT on chainA.
func (suite *KeeperTestSuite) TestSetChannel() {
ctx := suite.chainB.GetContext()
_, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1)
// create client and connections on both chains
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
// check for channel to be created on chainB
channelA := connA.NextTestChannel()
_, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetChannel(suite.chainA.GetContext(), channelA.PortID, channelA.ID)
suite.False(found)
counterparty2 := types.NewCounterparty(testPort2, testChannel2)
channel := types.NewChannel(
types.INIT, testChannelOrder,
counterparty2, []string{testConnectionIDA}, testChannelVersion,
)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel)
// init channel
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.NoError(err)
storedChannel, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetChannel(suite.chainA.GetContext(), channelA.PortID, channelA.ID)
expectedCounterparty := types.NewCounterparty(channelB.PortID, channelB.ID)
storedChannel, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1)
suite.True(found)
suite.Equal(channel, storedChannel)
suite.Equal(types.INIT, storedChannel.State)
suite.Equal(types.ORDERED, storedChannel.Ordering)
suite.Equal(expectedCounterparty, storedChannel.Counterparty)
}
// TestGetAllChannels creates multiple channels on chain A through various connections
// and tests their retrieval. 2 channels are on connA0 and 1 channel is on connA1
func (suite KeeperTestSuite) TestGetAllChannels() {
// Channel (Counterparty): A(C) -> C(B) -> B(A)
counterparty1 := types.NewCounterparty(testPort1, testChannel1)
counterparty2 := types.NewCounterparty(testPort2, testChannel2)
counterparty3 := types.NewCounterparty(testPort3, testChannel3)
clientA, clientB, connA0, connB0, testchannel0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
// channel0 on first connection on chainA
counterparty0 := types.Counterparty{
PortID: connB0.Channels[0].PortID,
ChannelID: connB0.Channels[0].ID,
}
// channel1 is second channel on first connection on chainA
testchannel1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA0, connB0, types.ORDERED)
counterparty1 := types.Counterparty{
PortID: connB0.Channels[1].PortID,
ChannelID: connB0.Channels[1].ID,
}
connA1, connB1 := suite.coordinator.CreateConnection(suite.chainA, suite.chainB, clientA, clientB)
// channel2 is on a second connection on chainA
testchannel2, _, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA1, connB1, types.UNORDERED)
suite.Require().NoError(err)
counterparty2 := types.Counterparty{
PortID: connB1.Channels[0].PortID,
ChannelID: connB1.Channels[0].ID,
}
channel0 := types.NewChannel(
types.OPEN, types.UNORDERED,
counterparty0, []string{connB0.ID}, ibctesting.ChannelVersion,
)
channel1 := types.NewChannel(
types.INIT, testChannelOrder,
counterparty3, []string{testConnectionIDA}, testChannelVersion,
types.OPEN, types.ORDERED,
counterparty1, []string{connB0.ID}, ibctesting.ChannelVersion,
)
channel2 := types.NewChannel(
types.INIT, testChannelOrder,
counterparty1, []string{testConnectionIDA}, testChannelVersion,
)
channel3 := types.NewChannel(
types.CLOSED, testChannelOrder,
counterparty2, []string{testConnectionIDA}, testChannelVersion,
types.INIT, types.UNORDERED,
counterparty2, []string{connB1.ID}, ibctesting.ChannelVersion,
)
expChannels := []types.IdentifiedChannel{
types.NewIdentifiedChannel(testPort1, testChannel1, channel1),
types.NewIdentifiedChannel(testPort2, testChannel2, channel2),
types.NewIdentifiedChannel(testPort3, testChannel3, channel3),
types.NewIdentifiedChannel(testchannel0.PortID, testchannel0.ID, channel0),
types.NewIdentifiedChannel(testchannel1.PortID, testchannel1.ID, channel1),
types.NewIdentifiedChannel(testchannel2.PortID, testchannel2.ID, channel2),
}
ctx := suite.chainB.GetContext()
ctxA := suite.chainA.GetContext()
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel1)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort2, testChannel2, channel2)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort3, testChannel3, channel3)
channels := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllChannels(ctx)
channels := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllChannels(ctxA)
suite.Require().Len(channels, len(expChannels))
suite.Require().Equal(expChannels, channels)
}
// TestGetAllSequences sets all packet sequences for two different channels on chain A and
// tests their retrieval.
func (suite KeeperTestSuite) TestGetAllSequences() {
seq1 := types.NewPacketSequence(testPort1, testChannel1, 1)
seq2 := types.NewPacketSequence(testPort2, testChannel2, 2)
_, _, connA, connB, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.UNORDERED)
expSeqs := []types.PacketSequence{seq1, seq2}
seq1 := types.NewPacketSequence(channelA0.PortID, channelA0.ID, 1)
seq2 := types.NewPacketSequence(channelA0.PortID, channelA0.ID, 2)
seq3 := types.NewPacketSequence(channelA1.PortID, channelA1.ID, 3)
ctx := suite.chainB.GetContext()
// seq1 should be overwritten by seq2
expSeqs := []types.PacketSequence{seq2, seq3}
for _, seq := range expSeqs {
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, seq.PortID, seq.ChannelID, seq.Sequence)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctx, seq.PortID, seq.ChannelID, seq.Sequence)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(ctx, seq.PortID, seq.ChannelID, seq.Sequence)
ctxA := suite.chainA.GetContext()
for _, seq := range []types.PacketSequence{seq1, seq2, seq3} {
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctxA, seq.PortID, seq.ChannelID, seq.Sequence)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctxA, seq.PortID, seq.ChannelID, seq.Sequence)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(ctxA, seq.PortID, seq.ChannelID, seq.Sequence)
}
sendSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketSendSeqs(ctx)
recvSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketRecvSeqs(ctx)
ackSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketAckSeqs(ctx)
suite.Require().Len(sendSeqs, 2)
suite.Require().Len(recvSeqs, 2)
suite.Require().Len(ackSeqs, 2)
sendSeqs := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllPacketSendSeqs(ctxA)
recvSeqs := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllPacketRecvSeqs(ctxA)
ackSeqs := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllPacketAckSeqs(ctxA)
suite.Len(sendSeqs, 2)
suite.Len(recvSeqs, 2)
suite.Len(ackSeqs, 2)
suite.Require().Equal(expSeqs, sendSeqs)
suite.Require().Equal(expSeqs, recvSeqs)
suite.Require().Equal(expSeqs, ackSeqs)
suite.Equal(expSeqs, sendSeqs)
suite.Equal(expSeqs, recvSeqs)
suite.Equal(expSeqs, ackSeqs)
}
// TestGetAllCommitmentsAcks creates a set of acks and packet commitments on two different
// channels on chain A and tests their retrieval.
func (suite KeeperTestSuite) TestGetAllCommitmentsAcks() {
ack1 := types.NewPacketAckCommitment(testPort1, testChannel1, 1, []byte("ack"))
ack2 := types.NewPacketAckCommitment(testPort1, testChannel1, 2, []byte("ack"))
comm1 := types.NewPacketAckCommitment(testPort1, testChannel1, 1, []byte("hash"))
comm2 := types.NewPacketAckCommitment(testPort1, testChannel1, 2, []byte("hash"))
_, _, connA, connB, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.UNORDERED)
expAcks := []types.PacketAckCommitment{ack1, ack2}
expCommitments := []types.PacketAckCommitment{comm1, comm2}
// channel 0 acks
ack1 := types.NewPacketAckCommitment(channelA0.PortID, channelA0.ID, 1, []byte("ack"))
ack2 := types.NewPacketAckCommitment(channelA0.PortID, channelA0.ID, 2, []byte("ack"))
ctx := suite.chainB.GetContext()
// duplicate ack
ack2dup := types.NewPacketAckCommitment(channelA0.PortID, channelA0.ID, 2, []byte("ack"))
for i := 0; i < 2; i++ {
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, expAcks[i].PortID, expAcks[i].ChannelID, expAcks[i].Sequence, expAcks[i].Hash)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, expCommitments[i].PortID, expCommitments[i].ChannelID, expCommitments[i].Sequence, expCommitments[i].Hash)
// channel 1 acks
ack3 := types.NewPacketAckCommitment(channelA1.PortID, channelA1.ID, 1, []byte("ack"))
// channel 0 packet commitments
comm1 := types.NewPacketAckCommitment(channelA0.PortID, channelA0.ID, 1, []byte("hash"))
comm2 := types.NewPacketAckCommitment(channelA0.PortID, channelA0.ID, 2, []byte("hash"))
// channel 1 packet commitments
comm3 := types.NewPacketAckCommitment(channelA1.PortID, channelA1.ID, 1, []byte("hash"))
comm4 := types.NewPacketAckCommitment(channelA1.PortID, channelA1.ID, 2, []byte("hash"))
expAcks := []types.PacketAckCommitment{ack1, ack2, ack3}
expCommitments := []types.PacketAckCommitment{comm1, comm2, comm3, comm4}
ctxA := suite.chainA.GetContext()
// set acknowledgements
for _, ack := range []types.PacketAckCommitment{ack1, ack2, ack2dup, ack3} {
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctxA, ack.PortID, ack.ChannelID, ack.Sequence, ack.Hash)
}
acks := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketAcks(ctx)
commitments := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketCommitments(ctx)
suite.Require().Len(acks, 2)
suite.Require().Len(commitments, 2)
// set packet commitments
for _, comm := range expCommitments {
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctxA, comm.PortID, comm.ChannelID, comm.Sequence, comm.Hash)
}
acks := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllPacketAcks(ctxA)
commitments := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllPacketCommitments(ctxA)
suite.Require().Len(acks, len(expAcks))
suite.Require().Len(commitments, len(expCommitments))
suite.Require().Equal(expAcks, acks)
suite.Require().Equal(expCommitments, commitments)
}
// TestSetSequence verifies that the keeper correctly sets the sequence counters.
func (suite *KeeperTestSuite) TestSetSequence() {
ctx := suite.chainB.GetContext()
_, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1)
suite.False(found)
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
_, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, testPort1, testChannel1)
suite.False(found)
ctxA := suite.chainA.GetContext()
one := uint64(1)
_, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, testPort1, testChannel1)
suite.False(found)
// initialized channel has next send seq of 1
seq, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctxA, channelA.PortID, channelA.ID)
suite.True(found)
suite.Equal(one, seq)
// initialized channel has next seq recv of 1
seq, found = suite.chainA.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctxA, channelA.PortID, channelA.ID)
suite.True(found)
suite.Equal(one, seq)
// initialized channel has next seq ack of
seq, found = suite.chainA.App.IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctxA, channelA.PortID, channelA.ID)
suite.True(found)
suite.Equal(one, seq)
nextSeqSend, nextSeqRecv, nextSeqAck := uint64(10), uint64(10), uint64(10)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, testPort1, testChannel1, nextSeqSend)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctx, testPort1, testChannel1, nextSeqRecv)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(ctx, testPort1, testChannel1, nextSeqAck)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctxA, channelA.PortID, channelA.ID, nextSeqSend)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctxA, channelA.PortID, channelA.ID, nextSeqRecv)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(ctxA, channelA.PortID, channelA.ID, nextSeqAck)
storedNextSeqSend, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1)
storedNextSeqSend, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctxA, channelA.PortID, channelA.ID)
suite.True(found)
suite.Equal(nextSeqSend, storedNextSeqSend)
storedNextSeqRecv, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1)
storedNextSeqRecv, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctxA, channelA.PortID, channelA.ID)
suite.True(found)
suite.Equal(nextSeqRecv, storedNextSeqRecv)
storedNextSeqAck, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, testPort1, testChannel1)
storedNextSeqAck, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctxA, channelA.PortID, channelA.ID)
suite.True(found)
suite.Equal(nextSeqAck, storedNextSeqAck)
}
// TestPacketCommitment does basic verification of setting and getting of packet commitments within
// the Channel Keeper.
func (suite *KeeperTestSuite) TestPacketCommitment() {
ctx := suite.chainB.GetContext()
seq := uint64(10)
storedCommitment := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq)
suite.Nil(storedCommitment)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, testPort1, testChannel1, seq, testPacketCommitment)
storedCommitment = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq)
suite.Equal(testPacketCommitment, storedCommitment)
}
// TestGetAllPacketCommitmentsAtChannel verifies that iterator returns all stored packet commitments
// for a specific channel.
// TestGetAllPacketCommitmentsAtChannel verifies that the keeper returns all stored packet
// commitments for a specific channel. The test will store consecutive commitments up to the
// value of "seq" and then add non-consecutive up to the value of "maxSeq". A final commitment
// with the value maxSeq + 1 is set on a different channel.
func (suite *KeeperTestSuite) TestGetAllPacketCommitmentsAtChannel() {
// setup
ctx := suite.chainB.GetContext()
_, _, connA, connB, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
// create second channel
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.UNORDERED)
ctxA := suite.chainA.GetContext()
expectedSeqs := make(map[uint64]bool)
hash := []byte("commitment")
seq := uint64(15)
maxSeq := uint64(25)
@ -236,289 +252,53 @@ func (suite *KeeperTestSuite) TestGetAllPacketCommitmentsAtChannel() {
// create consecutive commitments
for i := uint64(1); i < seq; i++ {
suite.chainB.storePacketCommitment(ctx, testPort1, testChannel1, i)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctxA, channelA.PortID, channelA.ID, i, hash)
expectedSeqs[i] = true
}
// add non-consecutive commitments
for i := seq; i < maxSeq; i += 2 {
suite.chainB.storePacketCommitment(ctx, testPort1, testChannel1, i)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctxA, channelA.PortID, channelA.ID, i, hash)
expectedSeqs[i] = true
}
// add sequence on different channel/port
suite.chainB.storePacketCommitment(ctx, testPort2, testChannel2, maxSeq+1)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctxA, channelA1.PortID, channelA1.ID, maxSeq+1, hash)
commitments := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketCommitmentsAtChannel(ctx, testPort1, testChannel1)
commitments := suite.chainA.App.IBCKeeper.ChannelKeeper.GetAllPacketCommitmentsAtChannel(ctxA, channelA.PortID, channelA.ID)
suite.Equal(len(expectedSeqs), len(commitments))
// ensure above for loops occurred
suite.NotEqual(0, len(commitments))
// verify that all the packet commitments were stored
for _, packet := range commitments {
suite.True(expectedSeqs[packet.Sequence])
suite.Equal(testPort1, packet.PortID)
suite.Equal(testChannel1, packet.ChannelID)
suite.Equal(channelA.PortID, packet.PortID)
suite.Equal(channelA.ID, packet.ChannelID)
suite.Equal(hash, packet.Hash)
// prevent duplicates from passing checks
expectedSeqs[packet.Sequence] = false
}
}
// TestSetPacketAcknowledgement verifies that packet acknowledgements are correctly
// set in the keeper.
func (suite *KeeperTestSuite) TestSetPacketAcknowledgement() {
ctx := suite.chainB.GetContext()
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
ctxA := suite.chainA.GetContext()
seq := uint64(10)
storedAckHash, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctx, testPort1, testChannel1, seq)
storedAckHash, found := suite.chainA.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctxA, channelA.PortID, channelA.ID, seq)
suite.False(found)
suite.Nil(storedAckHash)
ackHash := []byte("ackhash")
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, testPort1, testChannel1, seq, ackHash)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctxA, channelA.PortID, channelA.ID, seq, ackHash)
storedAckHash, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctx, testPort1, testChannel1, seq)
storedAckHash, found = suite.chainA.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctxA, channelA.PortID, channelA.ID, seq)
suite.True(found)
suite.Equal(ackHash, storedAckHash)
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func commitNBlocks(chain *TestChain, n int) {
for i := 0; i < n; i++ {
chain.App.Commit()
chain.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: chain.App.LastBlockHeight() + 1}})
}
}
// commit current block and start the next block with the provided time
func commitBlockWithNewTimestamp(chain *TestChain, timestamp int64) {
chain.App.Commit()
chain.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: chain.App.LastBlockHeight() + 1, Time: time.Unix(timestamp, 0)}})
}
// nolint: unused
func queryProof(chain *TestChain, key []byte) ([]byte, uint64) {
res := chain.App.Query(abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", host.StoreKey),
Height: chain.App.LastBlockHeight(),
Data: key,
Prove: true,
})
merkleProof := commitmenttypes.MerkleProof{
Proof: res.Proof,
}
proof, _ := chain.App.AppCodec().MarshalBinaryBare(&merkleProof)
return proof, uint64(res.Height)
}
type TestChain struct {
ClientID string
App *simapp.SimApp
Header ibctmtypes.Header
Vals *tmtypes.ValidatorSet
Signers []tmtypes.PrivValidator
}
func NewTestChain(clientID string) *TestChain {
privVal := tmtypes.NewMockPV()
pubKey, err := privVal.GetPubKey()
if err != nil {
panic(err)
}
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
signers := []tmtypes.PrivValidator{privVal}
now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, signers)
return &TestChain{
ClientID: clientID,
App: simapp.Setup(false),
Header: header,
Vals: valSet,
Signers: signers,
}
}
// Creates simple context for testing purposes
func (chain *TestChain) GetContext() sdk.Context {
return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.SignedHeader.Header.ChainID, Height: int64(chain.Header.GetHeight())})
}
// createClient will create a client for clientChain on targetChain
func (chain *TestChain) CreateClient(client *TestChain) error {
client.Header = nextHeader(client)
// Commit and create a new block on appTarget to get a fresh CommitID
client.App.Commit()
commitID := client.App.LastCommitID()
client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: int64(client.Header.GetHeight()), Time: client.Header.Time}})
// Set HistoricalInfo on client chain after Commit
ctxClient := client.GetContext()
validator := stakingtypes.NewValidator(
sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, stakingtypes.Description{},
)
validator.Status = sdk.Bonded
validator.Tokens = sdk.NewInt(1000000) // get one voting power
validators := []stakingtypes.Validator{validator}
histInfo := stakingtypes.HistoricalInfo{
Header: abci.Header{
AppHash: commitID.Hash,
},
Valset: validators,
}
client.App.StakingKeeper.SetHistoricalInfo(ctxClient, int64(client.Header.GetHeight()), histInfo)
// Create target ctx
ctxTarget := chain.GetContext()
// create client
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs())
if err != nil {
return err
}
_, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState())
if err != nil {
return err
}
return nil
// _, _, err := simapp.SignCheckDeliver(
// suite.T(),
// suite.cdc,
// suite.app.BaseApp,
// ctx.BlockHeader(),
// []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)},
// []uint64{baseAccount.GetAccountNumber()},
// []uint64{baseAccount.GetSequence()},
// true, true, accountPrivKey,
// )
}
func (chain *TestChain) updateClient(client *TestChain) {
// Create target ctx
ctxTarget := chain.GetContext()
// if clientState does not already exist, return without updating
_, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(
ctxTarget, client.ClientID,
)
if !found {
return
}
// always commit when updateClient and begin a new block
client.App.Commit()
commitID := client.App.LastCommitID()
client.Header = nextHeader(client)
client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: int64(client.Header.GetHeight()), Time: client.Header.Time}})
// Set HistoricalInfo on client chain after Commit
ctxClient := client.GetContext()
validator := stakingtypes.NewValidator(
sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, stakingtypes.Description{},
)
validator.Status = sdk.Bonded
validator.Tokens = sdk.NewInt(1000000)
validators := []stakingtypes.Validator{validator}
histInfo := stakingtypes.HistoricalInfo{
Header: abci.Header{
AppHash: commitID.Hash,
},
Valset: validators,
}
client.App.StakingKeeper.SetHistoricalInfo(ctxClient, int64(client.Header.GetHeight()), histInfo)
consensusState := ibctmtypes.ConsensusState{
Height: client.Header.GetHeight(),
Timestamp: client.Header.Time,
Root: commitmenttypes.NewMerkleRoot(commitID.Hash),
ValidatorSet: client.Vals,
}
chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState(
ctxTarget, client.ClientID, client.Header.GetHeight(), consensusState,
)
chain.App.IBCKeeper.ClientKeeper.SetClientState(
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs()),
)
// _, _, err := simapp.SignCheckDeliver(
// suite.T(),
// suite.cdc,
// suite.app.BaseApp,
// ctx.BlockHeader(),
// []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)},
// []uint64{baseAccount.GetAccountNumber()},
// []uint64{baseAccount.GetSequence()},
// true, true, accountPrivKey,
// )
// suite.Require().NoError(err)
}
func (chain *TestChain) createConnection(
connID, counterpartyConnID, clientID, counterpartyClientID string,
state connectiontypes.State,
) connectiontypes.ConnectionEnd {
counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, commitmenttypes.NewMerklePrefix(chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix().Bytes()))
connection := connectiontypes.ConnectionEnd{
State: state,
ClientID: clientID,
Counterparty: counterparty,
Versions: connectiontypes.GetCompatibleVersions(),
}
ctx := chain.GetContext()
chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection)
return connection
}
func (chain *TestChain) createChannel(
portID, channelID, counterpartyPortID, counterpartyChannelID string,
state types.State, order types.Order, connectionID string,
) types.Channel {
counterparty := types.NewCounterparty(counterpartyPortID, counterpartyChannelID)
// sets channel with given state
channel := types.NewChannel(state, order, counterparty,
[]string{connectionID}, testChannelVersion,
)
ctx := chain.GetContext()
chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel)
return channel
}
// storePacketCommitment is a helper function that sets a packet commitment in the Channel Keeper.
func (chain *TestChain) storePacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) {
chain.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, portID, channelID, sequence, testPacketCommitment)
}
// storeAcknowledgement is a helper function that sets a packet commitment in the Channel Keeper.
func (chain *TestChain) storeAcknowledgement(ctx sdk.Context, portID, channelID string, sequence uint64) {
chain.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, portID, channelID, sequence, testAcknowledgement)
}
func nextHeader(chain *TestChain) ibctmtypes.Header {
return ibctmtypes.CreateTestHeader(chain.Header.SignedHeader.Header.ChainID, int64(chain.Header.GetHeight())+1,
chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers)
}
// Mocked types
type mockSuccessPacket struct{}
// GetBytes returns the serialised packet data
func (mp mockSuccessPacket) GetBytes() []byte { return []byte("THIS IS A SUCCESS PACKET") }
type mockFailPacket struct{}
// GetBytes returns the serialised packet data (without timeout)
func (mp mockFailPacket) GetBytes() []byte { return []byte("THIS IS A FAILURE PACKET") }

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,8 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
@ -18,7 +19,7 @@ func (suite *KeeperTestSuite) TestQueryChannels() {
)
params := types.NewQueryAllChannelsParams(1, 100)
data, err := suite.cdc.MarshalJSON(params)
data, err := suite.chainA.App.AppCodec().MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
@ -33,88 +34,83 @@ func (suite *KeeperTestSuite) TestQueryChannels() {
{
"success with different connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 2)
// create channels on different connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
// create first connection/channel
clientA, clientB, _, _, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
types.NewIdentifiedChannel(
channelA0.PortID,
channelA0.ID,
suite.chainA.GetChannel(channelA0),
),
)
suite.chainA.createConnection(
testConnectionIDB, testConnectionIDA,
testClientIDB, testClientIDA,
connection.OPEN,
)
// create second connection
connA1, connB1 := suite.coordinator.CreateConnection(suite.chainA, suite.chainB, clientA, clientB)
// create second channel on second connection
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA1, connB1, types.ORDERED)
channels = append(channels,
types.NewIdentifiedChannel(testPort2, testChannel2,
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.ORDERED, testConnectionIDB,
),
types.NewIdentifiedChannel(
channelA1.PortID,
channelA1.ID,
suite.chainA.GetChannel(channelA1),
),
)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), channels)
suite.Require().NoError(err)
},
},
{
"success with singular connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 2)
// create channels on singular connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
// create first connection/channel
_, _, connA, connB, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
types.NewIdentifiedChannel(
channelA0.PortID,
channelA0.ID,
suite.chainA.GetChannel(channelA0),
),
)
// create second channel on the same connection
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.UNORDERED)
channels = append(channels,
types.NewIdentifiedChannel(testPort2, testChannel2,
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.UNORDERED, testConnectionIDA,
),
types.NewIdentifiedChannel(
channelA1.PortID,
channelA1.ID,
suite.chainA.GetChannel(channelA1),
),
)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), channels)
suite.Require().NoError(err)
},
},
{
"success no channels",
func() {
suite.SetupTest()
expRes, err = codec.MarshalJSONIndent(suite.cdc, []types.IdentifiedChannel{})
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), []types.IdentifiedChannel{})
suite.Require().NoError(err)
},
},
}
for i, tc := range testCases {
suite.SetupTest() // reset
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
bz, err := suite.chainA.Querier(suite.chainA.GetContext(), path, query)
suite.Require().NoError(err, "test case %d failed: %s", i, tc.name)
suite.Require().Equal(expRes, bz, "test case %d failed: %s", i, tc.name)
@ -127,18 +123,10 @@ func (suite *KeeperTestSuite) TestQueryConnectionChannels() {
var (
expRes []byte
params types.QueryConnectionChannelsParams
err error
)
params := types.NewQueryConnectionChannelsParams(testConnectionIDA, 1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
@ -146,101 +134,106 @@ func (suite *KeeperTestSuite) TestQueryConnectionChannels() {
{
"success with singular connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 2)
// create channels on singular connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
// create first connection/channel
_, _, connA, connB, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
types.NewIdentifiedChannel(
channelA0.PortID,
channelA0.ID,
suite.chainA.GetChannel(channelA0),
),
)
// create second channel on the same connection
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
channels = append(channels,
types.NewIdentifiedChannel(testPort2, testChannel2,
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.UNORDERED, testConnectionIDA,
),
types.NewIdentifiedChannel(
channelA1.PortID,
channelA1.ID,
suite.chainA.GetChannel(channelA1),
),
)
params = types.NewQueryConnectionChannelsParams(connA.ID, 1, 100)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), channels)
suite.Require().NoError(err)
},
},
{
"success multiple connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 1)
// create channels on different connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
// create first connection/channel
clientA, clientB, connA, _, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
types.NewIdentifiedChannel(
channelA0.PortID,
channelA0.ID,
suite.chainA.GetChannel(channelA0),
),
)
suite.chainA.createConnection(
testConnectionIDB, testConnectionIDA,
testClientIDB, testClientIDA,
connection.OPEN,
)
suite.chainA.createChannel(
testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.ORDERED, testConnectionIDB,
)
// create second connection
connA1, connB1 := suite.coordinator.CreateConnection(suite.chainA, suite.chainB, clientA, clientB)
// create second channel on second connection
suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA1, connB1, types.ORDERED)
params = types.NewQueryConnectionChannelsParams(connA.ID, 1, 100)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), channels)
suite.Require().NoError(err)
},
},
{
"success no channels",
func() {
suite.SetupTest()
expRes, err = codec.MarshalJSONIndent(suite.cdc, []types.IdentifiedChannel{})
// create connection but no channels
_, _, connA, _ := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
params = types.NewQueryConnectionChannelsParams(connA.ID, 1, 100)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), []types.IdentifiedChannel{})
suite.Require().NoError(err)
},
},
}
for i, tc := range testCases {
suite.SetupTest() // reset
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
data, err := suite.chainA.App.AppCodec().MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
bz, err := suite.chainA.Querier(suite.chainA.GetContext(), path, query)
suite.Require().NoError(err, "test case %d failed: %s", i, tc.name)
suite.Require().Equal(expRes, bz, "test case %d failed: %s", i, tc.name)
}
}
// TestQuerierChannelClientState verifies correct querying of client state associated
// with a channel end.
func (suite *KeeperTestSuite) TestQuerierChannelClientState() {
path := []string{types.SubModuleName, types.QueryChannelClientState}
params := types.NewQueryChannelClientStateParams(testPort1, testChannel1)
data, err := suite.cdc.MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
var (
clientID string
params types.QueryChannelClientStateParams
)
testCases := []struct {
name string
@ -249,77 +242,81 @@ func (suite *KeeperTestSuite) TestQuerierChannelClientState() {
}{
{
"channel not found",
func() {},
func() {
clientA, err := suite.coordinator.CreateClient(suite.chainA, suite.chainB, clientexported.Tendermint)
suite.Require().NoError(err)
clientID = clientA
params = types.NewQueryChannelClientStateParams("doesnotexist", "doesnotexist")
},
false,
},
{
"connection for channel not found",
func() {
_ = suite.chainA.createChannel(
testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
)
// connection for channel is deleted from state
clientA, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
channel := suite.chainA.GetChannel(channelA)
channel.ConnectionHops[0] = "doesnotexist"
// set connection hops to wrong connection ID
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), channelA.PortID, channelA.ID, channel)
clientID = clientA
params = types.NewQueryChannelClientStateParams(channelA.PortID, channelA.ID)
},
false,
},
{
"client state for channel's connection not found",
func() {
_ = suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
_ = suite.chainA.createChannel(
testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
)
clientA, _, connA, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
// setting connection to empty results in wrong clientID used
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), connA.ID, connectiontypes.ConnectionEnd{})
clientID = clientA
params = types.NewQueryChannelClientStateParams(channelA.PortID, channelA.ID)
},
false,
},
{
"success",
func() {
err = suite.chainA.CreateClient(suite.chainB)
suite.Require().NoError(err)
err = suite.chainB.CreateClient(suite.chainA)
suite.Require().NoError(err)
suite.chainA.createConnection(
testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA,
connection.OPEN,
)
suite.chainB.createConnection(
testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB,
connection.OPEN,
)
suite.chainA.createChannel(
testPort1, testChannel1, testPort2, testChannel2, types.INIT,
types.ORDERED, testConnectionIDB,
)
suite.chainB.createChannel(
testPort2, testChannel2, testPort1, testChannel1, types.TRYOPEN,
types.ORDERED, testConnectionIDA,
)
clientA, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
clientID = clientA
params = types.NewQueryChannelClientStateParams(channelA.PortID, channelA.ID)
},
true,
},
}
for i, tc := range testCases {
suite.SetupTest() // reset
tc.setup()
clientState, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), testClientIDB)
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
data, err := suite.chainA.App.AppCodec().MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
clientState, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientID)
bz, err := suite.chainA.Querier(suite.chainA.GetContext(), path, query)
if tc.expPass {
// set expected result
expRes, merr := codec.MarshalJSONIndent(suite.cdc, clientState)
expRes, merr := codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), clientState)
suite.Require().NoError(merr)
suite.Require().True(found)
suite.Require().True(found, "test case %d failed: %s", i, tc.name)
suite.Require().NoError(err, "test case %d failed: %s", i, tc.name)
suite.Require().Equal(string(expRes), string(bz), "test case %d failed: %s", i, tc.name)
} else {
suite.Require().False(found)
suite.Require().Error(err, "test case %d passed: %s", i, tc.name)
suite.Require().Nil(bz, "test case %d passed: %s", i, tc.name)
}
@ -332,17 +329,10 @@ func (suite *KeeperTestSuite) TestQueryPacketCommitments() {
var (
expRes []byte
params types.QueryPacketCommitmentsParams
err error
)
params := types.NewQueryPacketCommitmentsParams(testPort1, testChannel1, 1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
@ -350,58 +340,77 @@ func (suite *KeeperTestSuite) TestQueryPacketCommitments() {
{
"success",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
seq := uint64(1)
commitments := []uint64{}
// create several commitments on the same channel and port
for i := seq; i < 10; i++ {
suite.chainA.storePacketCommitment(ctx, testPort1, testChannel1, i)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), channelA.PortID, channelA.ID, i, []byte("ack"))
commitments = append(commitments, i)
}
expRes, err = codec.MarshalJSONIndent(suite.cdc, commitments)
params = types.NewQueryPacketCommitmentsParams(channelA.PortID, channelA.ID, 1, 100)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), commitments)
suite.Require().NoError(err)
},
},
{
"success with multiple channels",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
_, _, connA, connB, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
seq := uint64(1)
commitments := []uint64{}
// create several commitments on the same channel and port
for i := seq; i < 10; i++ {
suite.chainA.storePacketCommitment(ctx, testPort1, testChannel1, i)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), channelA0.PortID, channelA0.ID, i, []byte("ack"))
commitments = append(commitments, i)
}
// create second channel
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
// create several commitments on a different channel and port
for i := seq; i < 10; i++ {
suite.chainA.storePacketCommitment(ctx, testPort2, testChannel2, i)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), channelA1.PortID, channelA1.ID, i, []byte("ack"))
}
expRes, err = codec.MarshalJSONIndent(suite.cdc, commitments)
params = types.NewQueryPacketCommitmentsParams(channelA0.PortID, channelA1.ID, 1, 100)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), commitments)
suite.Require().NoError(err)
},
},
{
"success no packet commitments",
func() {
suite.SetupTest()
expRes, err = codec.MarshalJSONIndent(suite.cdc, []uint64{})
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
params = types.NewQueryPacketCommitmentsParams(channelA.PortID, channelA.ID, 1, 100)
expRes, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), []uint64{})
suite.Require().NoError(err)
},
},
}
for i, tc := range testCases {
suite.SetupTest() // reset
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
data, err := suite.chainA.App.AppCodec().MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
bz, err := suite.chainA.Querier(suite.chainA.GetContext(), path, query)
suite.Require().NoError(err, "test case %d failed: %s", i, tc.name)
suite.Require().Equal(expRes, bz, "test case %d failed: %s", i, tc.name)
@ -419,17 +428,10 @@ func (suite *KeeperTestSuite) TestQueryUnrelayedAcks() {
var (
expResAck []byte
expResSend []byte
params types.QueryUnrelayedPacketsParams
err error
)
params := types.NewQueryUnrelayedPacketsParams(testPort1, testChannel1, sequences, 1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
@ -437,25 +439,27 @@ func (suite *KeeperTestSuite) TestQueryUnrelayedAcks() {
{
"success",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
unrelayedAcks := []uint64{}
unrelayedSends := []uint64{}
// create acknowledgements for first 3 sequences
for _, seq := range sequences {
if seq < 4 {
suite.chainA.storeAcknowledgement(ctx, testPort1, testChannel1, seq)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), channelA.PortID, channelA.ID, seq, []byte("ack"))
unrelayedAcks = append(unrelayedAcks, seq)
} else {
unrelayedSends = append(unrelayedSends, seq)
}
}
expResAck, err = codec.MarshalJSONIndent(suite.cdc, unrelayedAcks)
params = types.NewQueryUnrelayedPacketsParams(channelA.PortID, channelA.ID, sequences, 1, 100)
expResAck, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), unrelayedAcks)
suite.Require().NoError(err)
expResSend, err = codec.MarshalJSONIndent(suite.cdc, unrelayedSends)
expResSend, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), unrelayedSends)
suite.Require().NoError(err)
},
@ -463,64 +467,80 @@ func (suite *KeeperTestSuite) TestQueryUnrelayedAcks() {
{
"success with multiple channels",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
_, _, connA, connB, channelA0, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
ctxA := suite.chainA.GetContext()
unrelayedAcks := []uint64{}
unrelayedSends := []uint64{}
// create acknowledgements for first 3 sequences
for _, seq := range sequences {
if seq < 4 {
suite.chainA.storeAcknowledgement(ctx, testPort1, testChannel1, seq)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctxA, channelA0.PortID, channelA0.ID, seq, []byte("ack"))
unrelayedAcks = append(unrelayedAcks, seq)
} else {
unrelayedSends = append(unrelayedSends, seq)
}
}
// create second channel
channelA1, _ := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.UNORDERED)
// create acknowledgements for other sequences on different channel/port
for _, seq := range sequences {
if seq >= 4 {
suite.chainA.storeAcknowledgement(ctx, testPort2, testChannel2, seq)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctxA, channelA1.PortID, channelA1.ID, seq, []byte("ack"))
}
}
expResAck, err = codec.MarshalJSONIndent(suite.cdc, unrelayedAcks)
params = types.NewQueryUnrelayedPacketsParams(channelA0.PortID, channelA0.ID, sequences, 1, 100)
expResAck, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), unrelayedAcks)
suite.Require().NoError(err)
expResSend, err = codec.MarshalJSONIndent(suite.cdc, unrelayedSends)
expResSend, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), unrelayedSends)
suite.Require().NoError(err)
},
},
{
"success no unrelayed acks",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
// create acknowledgements for all sequences
for _, seq := range sequences {
suite.chainA.storeAcknowledgement(ctx, testPort1, testChannel1, seq)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), channelA.PortID, channelA.ID, seq, []byte("ack"))
}
expResSend, err = codec.MarshalJSONIndent(suite.cdc, []uint64{})
params = types.NewQueryUnrelayedPacketsParams(channelA.PortID, channelA.ID, sequences, 1, 100)
expResSend, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), []uint64{})
suite.Require().NoError(err)
expResAck, err = codec.MarshalJSONIndent(suite.cdc, sequences)
expResAck, err = codec.MarshalJSONIndent(suite.chainA.App.AppCodec(), sequences)
suite.Require().NoError(err)
},
},
}
for i, tc := range testCases {
suite.SetupTest() // reset
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), pathAck, query)
data, err := suite.chainA.App.AppCodec().MarshalJSON(params)
suite.Require().NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
bz, err := suite.chainA.Querier(suite.chainA.GetContext(), pathAck, query)
suite.Require().NoError(err, "test case %d failed: %s", i, tc.name)
suite.Require().Equal(expResAck, bz, "test case %d failed: %s", i, tc.name)
bz, err = suite.querier(suite.chainA.GetContext(), pathSend, query)
bz, err = suite.chainA.Querier(suite.chainA.GetContext(), pathSend, query)
suite.Require().NoError(err, "test case %d failed: %s", i, tc.name)
suite.Require().Equal(expResSend, bz, "test case %d failed: %s", i, tc.name)

View File

@ -4,111 +4,154 @@ import (
"fmt"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
// TestTimeoutPacket test the TimeoutPacket call on chainA by ensuring the timeout has passed
// on chainB, but that no ack has been written yet. Test cases expected to reach proof
// verification must specify which proof to use using the ordered bool.
func (suite *KeeperTestSuite) TestTimeoutPacket() {
counterparty := types.NewCounterparty(testPort2, testChannel2)
packetKey := host.KeyPacketAcknowledgement(testPort2, testChannel2, 2)
var (
packet types.Packet
nextSeqRecv uint64
ordered bool
)
testCases := []testCase{
{"success", func() {
nextSeqRecv = 1
packet = types.NewPacket(newMockTimeoutPacket().GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), 1, disabledTimeoutTimestamp)
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.UNORDERED, testConnectionIDA)
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, types.OPEN, types.UNORDERED, testConnectionIDB)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
{"success: ORDERED", func() {
ordered = true
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, true},
{"channel not found", func() {}, false},
{"success: UNORDERED", func() {
ordered = false
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, true},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"channel not open", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.CLOSED, types.ORDERED, testConnectionIDA)
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
suite.Require().NoError(err)
}, false},
{"packet source port ≠ channel counterparty port", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
{"packet destination port ≠ channel counterparty port", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
// use wrong port for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"packet source channel ID ≠ channel counterparty channel ID", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, types.OPEN, types.ORDERED, testConnectionIDA)
{"packet destination channel ID ≠ channel counterparty channel ID", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
// use wrong channel for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"connection not found", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
channelA := ibctesting.TestChannel{PortID: portID, ID: channelIDA}
channelB := ibctesting.TestChannel{PortID: portID, ID: channelIDB}
// pass channel check
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(
suite.chainA.GetContext(),
channelA.PortID, channelA.ID,
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelB.PortID, channelB.ID), []string{connIDA}, ibctesting.ChannelVersion),
)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"timeout", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 10, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, false},
{"packet already received ", func() {
ordered = true
nextSeqRecv = 2
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, false},
{"packet hasn't been sent", func() {
nextSeqRecv = 1
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
clientA, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, false},
{"next seq receive verification failed", func() {
nextSeqRecv = 1
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
// set ordered to false resulting in wrong proof provided
ordered = false
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, false},
{"packet ack verification failed", func() {
nextSeqRecv = 1
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.UNORDERED, testConnectionIDA)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
// set ordered to true resulting in wrong proof provided
ordered = true
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
}, false},
}
for i, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
var (
proof []byte
proofHeight uint64
)
suite.SetupTest() // reset
nextSeqRecv = 1 // must be explicitly changed
tc.malleate()
ctx := suite.chainB.GetContext()
orderedPacketKey := host.KeyNextSequenceRecv(packet.GetDestPort(), packet.GetDestChannel())
unorderedPacketKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
proof, proofHeight := queryProof(suite.chainA, packetKey)
if ordered {
proof, proofHeight = suite.chainB.QueryProof(orderedPacketKey)
} else {
proof, proofHeight = suite.chainB.QueryProof(unorderedPacketKey)
}
_, err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutPacket(suite.chainA.GetContext(), packet, proof, proofHeight, nextSeqRecv)
if tc.expPass {
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, proof, proofHeight+1, nextSeqRecv)
suite.Require().NoError(err)
suite.Require().NotNil(packetOut)
} else {
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, proof, proofHeight, nextSeqRecv)
suite.Require().Error(err)
suite.Require().Nil(packetOut)
}
})
}
}
// TestTimeoutExectued verifies that packet commitments are deleted after
// capabilities are verified.
// TestTimeoutExectued verifies that packet commitments are deleted on chainA after the
// channel capabilities are verified.
func (suite *KeeperTestSuite) TestTimeoutExecuted() {
sequence := uint64(1)
var (
packet types.Packet
chanCap *capabilitytypes.Capability
@ -116,14 +159,24 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() {
testCases := []testCase{
{"success ORDERED", func() {
packet = types.NewPacket(newMockTimeoutPacket().GetBytes(), 1, testPort1, testChannel1, testPort2, testChannel2, timeoutHeight, disabledTimeoutTimestamp)
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), sequence, types.CommitPacket(packet))
_, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"channel not found", func() {}, false},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"incorrect capability", func() {
packet = types.NewPacket(newMockTimeoutPacket().GetBytes(), 1, testPort1, testChannel1, testPort2, testChannel2, timeoutHeight, disabledTimeoutTimestamp)
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
_, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
chanCap = capabilitytypes.NewCapability(100)
}, false},
}
@ -133,16 +186,10 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() {
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
suite.SetupTest() // reset
var err error
chanCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability(
suite.chainA.GetContext(), host.ChannelCapabilityPath(testPort1, testChannel1),
)
suite.Require().NoError(err, "could not create capability")
tc.malleate()
err = suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutExecuted(suite.chainA.GetContext(), chanCap, packet)
pc := suite.chainA.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), sequence)
err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutExecuted(suite.chainA.GetContext(), chanCap, packet)
pc := suite.chainA.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
if tc.expPass {
suite.NoError(err)
@ -154,87 +201,131 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() {
}
}
// TestTimeoutOnClose tests the call TimeoutOnClose on chainA by closing the corresponding
// channel on chainB after the packet commitment has been created.
func (suite *KeeperTestSuite) TestTimeoutOnClose() {
channelKey := host.KeyChannel(testPort2, testChannel2)
unorderedPacketKey := host.KeyPacketAcknowledgement(testPort2, testChannel2, 2)
orderedPacketKey := host.KeyNextSequenceRecv(testPort2, testChannel2)
counterparty := types.NewCounterparty(testPort2, testChannel2)
var (
packet types.Packet
chanCap *capabilitytypes.Capability
nextSeqRecv uint64
ordered bool
)
testCases := []testCase{
{"success on ordered channel", func() {
{"success: ORDERED", func() {
ordered = true
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, types.CLOSED, types.ORDERED, testConnectionIDB) // channel on chainA is closed
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, nextSeqRecv)
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"success on unordered channel", func() {
{"success: UNORDERED", func() {
ordered = false
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateClient(suite.chainA)
suite.chainA.CreateClient(suite.chainB)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.UNORDERED, testConnectionIDA)
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, types.CLOSED, types.UNORDERED, testConnectionIDB) // channel on chainA is closed
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"channel not found", func() {}, false},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"packet dest port ≠ channel counterparty port", func() {
ordered = true
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
// use wrong port for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet dest channel ID ≠ channel counterparty channel ID", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, types.OPEN, types.ORDERED, testConnectionIDA)
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
// use wrong channel for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"connection not found", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
channelA := ibctesting.TestChannel{PortID: portID, ID: channelIDA}
channelB := ibctesting.TestChannel{PortID: portID, ID: channelIDB}
// pass channel check
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(
suite.chainA.GetContext(),
channelA.PortID, channelA.ID,
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelB.PortID, channelB.ID), []string{connIDA}, ibctesting.ChannelVersion),
)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
// create chancap
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet hasn't been sent", func() {
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet already received", func() {
nextSeqRecv = 2
ordered = true
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"channel verification failed", func() {
ordered = false
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateClient(suite.chainA)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.UNORDERED, testConnectionIDA)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv)
ordered = true
_, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"next seq receive verification failed", func() {
ordered = true
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateClient(suite.chainA)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv)
// set ordered to false providing the wrong proof for ORDERED case
ordered = false
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet ack verification failed", func() {
ordered = false
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateClient(suite.chainA)
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.UNORDERED, testConnectionIDA)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet))
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv)
// set ordered to true providing the wrong proof for UNORDERED case
ordered = true
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"channel capability not found", func() {
ordered = true
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB := suite.coordinator.CreateChannel(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
chanCap = capabilitytypes.NewCapability(100)
}, false},
}
@ -244,42 +335,29 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() {
var proof []byte
suite.SetupTest() // reset
nextSeqRecv = 1 // must be explicitly changed
tc.malleate()
suite.chainB.updateClient(suite.chainA)
suite.chainA.updateClient(suite.chainB)
proofClosed, proofHeight := queryProof(suite.chainA, channelKey)
channelKey := host.KeyChannel(packet.GetDestPort(), packet.GetDestChannel())
unorderedPacketKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
orderedPacketKey := host.KeyNextSequenceRecv(packet.GetDestPort(), packet.GetDestChannel())
proofClosed, proofHeight := suite.chainB.QueryProof(channelKey)
if ordered {
proof, _ = queryProof(suite.chainA, orderedPacketKey)
proof, _ = suite.chainB.QueryProof(orderedPacketKey)
} else {
proof, _ = queryProof(suite.chainA, unorderedPacketKey)
proof, _ = suite.chainB.QueryProof(unorderedPacketKey)
}
ctx := suite.chainB.GetContext()
cap, err := suite.chainB.App.ScopedIBCKeeper.NewCapability(ctx, host.ChannelCapabilityPath(testPort1, testChannel1))
suite.Require().NoError(err)
_, err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(suite.chainA.GetContext(), chanCap, packet, proof, proofClosed, proofHeight, nextSeqRecv)
if tc.expPass {
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, cap, packet, proof, proofClosed, proofHeight+1, nextSeqRecv)
suite.Require().NoError(err)
suite.Require().NotNil(packetOut)
} else {
// switch the proofs to invalidate them
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, cap, packet, proofClosed, proof, proofHeight+1, nextSeqRecv)
suite.Require().Error(err)
suite.Require().Nil(packetOut)
}
})
}
}
type mockTimeoutPacket struct{}
func newMockTimeoutPacket() mockTimeoutPacket {
return mockTimeoutPacket{}
}
// GetBytes returns the serialised packet data (without timeout)
func (mp mockTimeoutPacket) GetBytes() []byte { return []byte("THIS IS A TIMEOUT PACKET") }

View File

@ -12,7 +12,7 @@ import (
var _ sdk.Msg = &MsgChannelOpenInit{}
// NewMsgChannelOpenInit creates a new MsgChannelCloseInit MsgChannelOpenInit
// NewMsgChannelOpenInit creates a new MsgChannelOpenInit
func NewMsgChannelOpenInit(
portID, channelID string, version string, channelOrder Order, connectionHops []string,
counterpartyPortID, counterpartyChannelID string, signer sdk.AccAddress,

View File

@ -2,6 +2,7 @@ package testing
import (
"fmt"
"strconv"
"testing"
"time"
@ -9,14 +10,20 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/tendermint/tendermint/crypto/tmhash"
tmmath "github.com/tendermint/tendermint/libs/math"
lite "github.com/tendermint/tendermint/lite2"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
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"
@ -30,17 +37,18 @@ const (
UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3
MaxClockDrift time.Duration = time.Second * 10
ConnectionVersion = "1.0"
ChannelVersion = "1.0"
ConnectionVersion = "1.0.0"
ChannelVersion = "ics20-1"
InvalidID = "IDisInvalid"
ClientIDPrefix = "clientFor"
ConnectionIDPrefix = "connectionid"
ChannelIDPrefix = "channelid"
PortIDPrefix = "portid"
maxInt = int(^uint(0) >> 1)
)
var (
DefaultTrustLevel tmmath.Fraction = lite.DefaultTrustLevel
TestHash = []byte("TESTING HASH")
)
// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI
@ -64,9 +72,8 @@ type TestChain struct {
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
ClientIDs []string // ClientID's used on this chain
Connections []*TestConnection // track connectionID's created for this chain
}
// NewTestChain initializes a new TestChain instance with a single validator set using a
@ -88,43 +95,40 @@ func NewTestChain(t *testing.T, chainID string) *TestChain {
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
// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
simapp.AddTestAddrsFromPubKeys(app, ctx, []crypto.PubKey{senderPrivKey.PubKey()}, sdk.NewInt(10000000000))
acc := app.AccountKeeper.GetAccount(ctx, sdk.AccAddress(senderPrivKey.PubKey().Address()))
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
balance := banktypes.Balance{
Address: acc.GetAddress(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
}
app := simapp.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance)
// 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),
Height: 1,
Time: globalStartTime,
}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
lastHeader := ibctmtypes.CreateTestHeader(chainID, 1, globalStartTime, valSet, signers)
// create an account to send transactions from
return &TestChain{
chain := &TestChain{
t: t,
ChainID: chainID,
App: app,
LastHeader: lastHeader,
CurrentHeader: header,
Querier: keeper.NewQuerier(*app.IBCKeeper),
Vals: valSet,
Signers: signers,
senderPrivKey: senderPrivKey,
SenderAccount: acc,
ClientIDs: make([]string, 0),
Connections: make([]*TestConnection, 0),
}
chain.NextBlock()
return chain
}
// GetContext returns the current context for the application.
@ -133,11 +137,11 @@ func (chain *TestChain) GetContext() sdk.Context {
}
// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof
// for the query and the height at which the query was performed.
// for the query and the height at which the proof will succeed on a tendermint verifier.
func (chain *TestChain) QueryProof(key []byte) ([]byte, uint64) {
res := chain.App.Query(abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", host.StoreKey),
Height: chain.App.LastBlockHeight(),
Height: chain.App.LastBlockHeight() - 1,
Data: key,
Prove: true,
})
@ -149,7 +153,10 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, uint64) {
proof, err := chain.App.AppCodec().MarshalBinaryBare(&merkleProof)
require.NoError(chain.t, err)
return proof, uint64(res.Height)
// proof height + 1 is returned as the proof created corresponds to the height the proof
// was created in the IAVL tree. Tendermint and subsequently the clients that rely on it
// have heights 1 above the IAVL tree. Thus we return proof height + 1
return proof, uint64(res.Height) + 1
}
// NextBlock sets the last header to the current header and increments the current header to be
@ -158,18 +165,19 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, uint64) {
// 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,
)
chain.LastHeader = chain.CreateTMClientHeader()
// increment the current header
chain.CurrentHeader = abci.Header{
Height: chain.CurrentHeader.Height + 1,
Time: chain.CurrentHeader.Time,
Height: chain.App.LastBlockHeight() + 1,
AppHash: chain.App.LastCommitID().Hash,
// NOTE: the time is increased by the coordinator to maintain time synchrony amongst
// chains.
Time: chain.CurrentHeader.Time,
}
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
}
// SendMsg delivers a transaction through the application. It updates the senders sequence
@ -198,11 +206,51 @@ func (chain *TestChain) SendMsg(msg sdk.Msg) error {
return nil
}
// GetClientState retreives the client state for the provided clientID. The client is
// expected to exist otherwise testing will fail.
func (chain *TestChain) GetClientState(clientID string) clientexported.ClientState {
clientState, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(chain.GetContext(), clientID)
require.True(chain.t, found)
return clientState
}
// GetConnection retreives an IBC Connection for the provided TestConnection. The
// connection is expected to exist otherwise testing will fail.
func (chain *TestChain) GetConnection(testConnection *TestConnection) connectiontypes.ConnectionEnd {
connection, found := chain.App.IBCKeeper.ConnectionKeeper.GetConnection(chain.GetContext(), testConnection.ID)
require.True(chain.t, found)
return connection
}
// GetChannel retreives an IBC Channel for the provided TestChannel. The channel
// is expected to exist otherwise testing will fail.
func (chain *TestChain) GetChannel(testChannel TestChannel) channeltypes.Channel {
channel, found := chain.App.IBCKeeper.ChannelKeeper.GetChannel(chain.GetContext(), testChannel.PortID, testChannel.ID)
require.True(chain.t, found)
return channel
}
// GetAcknowledgement retreives an acknowledgement for the provided packet. If the
// acknowledgement does not exist then testing will fail.
func (chain *TestChain) GetAcknowledgement(packet channelexported.PacketI) []byte {
ack, found := chain.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
require.True(chain.t, found)
return ack
}
// GetPrefix returns the prefix for used by a chain in connection creation
func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix {
return commitmenttypes.NewMerklePrefix(chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix().Bytes())
}
// 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))
clientID := "client" + strconv.Itoa(len(chain.ClientIDs)) + "For" + counterpartyChainID
chain.ClientIDs = append(chain.ClientIDs, clientID)
return clientID
}
@ -210,9 +258,9 @@ func (chain *TestChain) NewClientID(counterpartyChainID string) string {
// 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{
func (chain *TestChain) NewTestConnection(clientID, counterpartyClientID string) *TestConnection {
connectionID := ConnectionIDPrefix + strconv.Itoa(len(chain.Connections))
conn := &TestConnection{
ID: connectionID,
ClientID: clientID,
CounterpartyClientID: counterpartyClientID,
@ -222,23 +270,6 @@ func (chain *TestChain) NewTestConnection(clientID, counterpartyClientID string)
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 {
@ -263,17 +294,65 @@ func (chain *TestChain) UpdateTMClient(counterparty *TestChain, clientID string)
return chain.SendMsg(msg)
}
// CreateTMClientHeader creates a TM header to update the TM client.
func (chain *TestChain) CreateTMClientHeader() ibctmtypes.Header {
vsetHash := chain.Vals.Hash()
tmHeader := tmtypes.Header{
Version: version.Consensus{Block: 2, App: 2},
ChainID: chain.ChainID,
Height: chain.CurrentHeader.Height,
Time: chain.CurrentHeader.Time,
LastBlockID: MakeBlockID(make([]byte, tmhash.Size), maxInt, make([]byte, tmhash.Size)),
LastCommitHash: chain.App.LastCommitID().Hash,
DataHash: tmhash.Sum([]byte("data_hash")),
ValidatorsHash: vsetHash,
NextValidatorsHash: vsetHash,
ConsensusHash: tmhash.Sum([]byte("consensus_hash")),
AppHash: chain.CurrentHeader.AppHash,
LastResultsHash: tmhash.Sum([]byte("last_results_hash")),
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: chain.Vals.Proposer.Address,
}
hhash := tmHeader.Hash()
blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set")))
voteSet := tmtypes.NewVoteSet(chain.ChainID, chain.CurrentHeader.Height, 1, tmtypes.PrecommitType, chain.Vals)
commit, err := tmtypes.MakeCommit(blockID, chain.CurrentHeader.Height, 1, voteSet, chain.Signers, chain.CurrentHeader.Time)
require.NoError(chain.t, err)
signedHeader := tmtypes.SignedHeader{
Header: &tmHeader,
Commit: commit,
}
return ibctmtypes.Header{
SignedHeader: signedHeader,
ValidatorSet: chain.Vals,
}
}
// Copied unimported test functions from tmtypes to use them here
func MakeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.BlockID {
return tmtypes.BlockID{
Hash: hash,
PartsHeader: tmtypes.PartSetHeader{
Total: partSetSize,
Hash: partSetHash,
},
}
}
// ConnectionOpenInit will construct and execute a MsgConnectionOpenInit.
func (chain *TestChain) ConnectionOpenInit(
counterparty *TestChain,
connection, counterpartyConnection TestConnection,
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,
counterparty.GetPrefix(),
chain.SenderAccount.GetAddress(),
)
return chain.SendMsg(msg)
@ -282,21 +361,23 @@ func (chain *TestChain) ConnectionOpenInit(
// ConnectionOpenTry will construct and execute a MsgConnectionOpenTry.
func (chain *TestChain) ConnectionOpenTry(
counterparty *TestChain,
connection, counterpartyConnection TestConnection,
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))
// retrieve consensus state to provide proof for
consState, found := counterparty.App.IBCKeeper.ClientKeeper.GetLatestClientConsensusState(counterparty.GetContext(), counterpartyConnection.ClientID)
require.True(chain.t, found)
consensusHeight := consState.GetHeight()
consensusKey := prefixedClientKey(counterpartyConnection.ClientID, host.KeyConsensusState(consensusHeight))
proofConsensus, _ := counterparty.QueryProof(consensusKey)
msg := connectiontypes.NewMsgConnectionOpenTry(
connection.ID, connection.ClientID,
counterpartyConnection.ID, connection.CounterpartyClientID,
prefix, []string{ConnectionVersion},
counterpartyConnection.ID, counterpartyConnection.ClientID,
counterparty.GetPrefix(), []string{ConnectionVersion},
proofInit, proofConsensus,
proofHeight, consensusHeight,
chain.SenderAccount.GetAddress(),
@ -307,13 +388,17 @@ func (chain *TestChain) ConnectionOpenTry(
// ConnectionOpenAck will construct and execute a MsgConnectionOpenAck.
func (chain *TestChain) ConnectionOpenAck(
counterparty *TestChain,
connection, counterpartyConnection TestConnection,
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))
// retrieve consensus state to provide proof for
consState, found := counterparty.App.IBCKeeper.ClientKeeper.GetLatestClientConsensusState(counterparty.GetContext(), counterpartyConnection.ClientID)
require.True(chain.t, found)
consensusHeight := consState.GetHeight()
consensusKey := prefixedClientKey(counterpartyConnection.ClientID, host.KeyConsensusState(consensusHeight))
proofConsensus, _ := counterparty.QueryProof(consensusKey)
msg := connectiontypes.NewMsgConnectionOpenAck(
@ -329,7 +414,7 @@ func (chain *TestChain) ConnectionOpenAck(
// ConnectionOpenConfirm will construct and execute a MsgConnectionOpenConfirm.
func (chain *TestChain) ConnectionOpenConfirm(
counterparty *TestChain,
connection, counterpartyConnection TestConnection,
connection, counterpartyConnection *TestConnection,
) error {
connectionKey := host.KeyConnection(counterpartyConnection.ID)
proof, height := counterparty.QueryProof(connectionKey)
@ -342,33 +427,87 @@ func (chain *TestChain) ConnectionOpenConfirm(
return chain.SendMsg(msg)
}
// ChannelOpenInit will construct and execute a MsgChannelOpenInit.
func (chain *TestChain) ChannelOpenInit(
// CreatePortCapability binds and claims a capability for the given portID if it does not
// already exist. This function will fail testing on any resulting error.
func (chain *TestChain) CreatePortCapability(portID string) {
// check if the portId is already binded, if not bind it
_, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.PortPath(portID))
if !ok {
cap, err := chain.App.ScopedIBCKeeper.NewCapability(chain.GetContext(), host.PortPath(portID))
require.NoError(chain.t, err)
err = chain.App.ScopedTransferKeeper.ClaimCapability(chain.GetContext(), cap, host.PortPath(portID))
require.NoError(chain.t, err)
}
chain.App.Commit()
chain.NextBlock()
}
// GetPortCapability returns the port capability for the given portID. The capability must
// exist, otherwise testing will fail.
func (chain *TestChain) GetPortCapability(portID string) *capabilitytypes.Capability {
cap, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.PortPath(portID))
require.True(chain.t, ok)
return cap
}
// CreateChannelCapability binds and claims a capability for the given portID and channelID
// if it does not already exist. This function will fail testing on any resulting error.
func (chain *TestChain) CreateChannelCapability(portID, channelID string) {
capName := host.ChannelCapabilityPath(portID, channelID)
// check if the portId is already binded, if not bind it
_, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), capName)
if !ok {
cap, err := chain.App.ScopedIBCKeeper.NewCapability(chain.GetContext(), capName)
require.NoError(chain.t, err)
err = chain.App.ScopedTransferKeeper.ClaimCapability(chain.GetContext(), cap, capName)
require.NoError(chain.t, err)
}
chain.App.Commit()
chain.NextBlock()
}
// GetChannelCapability returns the channel capability for the given portID and channelID.
// The capability must exist, otherwise testing will fail.
func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabilitytypes.Capability {
cap, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.ChannelCapabilityPath(portID, channelID))
require.True(chain.t, ok)
return cap
}
// ChanOpenInit will construct and execute a MsgChannelOpenInit.
func (chain *TestChain) ChanOpenInit(
ch, counterparty TestChannel,
order channeltypes.Order,
connectionID string,
) error {
msg := channeltypes.NewMsgChannelOpenInit(
ch.PortID, ch.ChannelID,
ch.PortID, ch.ID,
ChannelVersion, order, []string{connectionID},
counterparty.PortID, counterparty.ChannelID,
counterparty.PortID, counterparty.ID,
chain.SenderAccount.GetAddress(),
)
return chain.SendMsg(msg)
}
// ChannelOpenTry will construct and execute a MsgChannelOpenTry.
func (chain *TestChain) ChannelOpenTry(
ch, counterparty TestChannel,
// ChanOpenTry will construct and execute a MsgChannelOpenTry.
func (chain *TestChain) ChanOpenTry(
counterparty *TestChain,
ch, counterpartyCh TestChannel,
order channeltypes.Order,
connectionID string,
) error {
proof, height := chain.QueryProof(host.KeyConnection(connectionID))
proof, height := counterparty.QueryProof(host.KeyChannel(counterpartyCh.PortID, counterpartyCh.ID))
msg := channeltypes.NewMsgChannelOpenTry(
ch.PortID, ch.ChannelID,
ch.PortID, ch.ID,
ChannelVersion, order, []string{connectionID},
counterparty.PortID, counterparty.ChannelID,
counterpartyCh.PortID, counterpartyCh.ID,
ChannelVersion,
proof, height,
chain.SenderAccount.GetAddress(),
@ -376,15 +515,15 @@ func (chain *TestChain) ChannelOpenTry(
return chain.SendMsg(msg)
}
// ChannelOpenAck will construct and execute a MsgChannelOpenAck.
func (chain *TestChain) ChannelOpenAck(
ch, counterparty TestChannel,
connectionID string,
// ChanOpenAck will construct and execute a MsgChannelOpenAck.
func (chain *TestChain) ChanOpenAck(
counterparty *TestChain,
ch, counterpartyCh TestChannel,
) error {
proof, height := chain.QueryProof(host.KeyConnection(connectionID))
proof, height := counterparty.QueryProof(host.KeyChannel(counterpartyCh.PortID, counterpartyCh.ID))
msg := channeltypes.NewMsgChannelOpenAck(
ch.PortID, ch.ChannelID,
ch.PortID, ch.ID,
ChannelVersion,
proof, height,
chain.SenderAccount.GetAddress(),
@ -392,17 +531,70 @@ func (chain *TestChain) ChannelOpenAck(
return chain.SendMsg(msg)
}
// ChannelOpenConfirm will construct and execute a MsgChannelOpenConfirm.
func (chain *TestChain) ChannelOpenConfirm(
ch, counterparty TestChannel,
connectionID string,
// ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm.
func (chain *TestChain) ChanOpenConfirm(
counterparty *TestChain,
ch, counterpartyCh TestChannel,
) error {
proof, height := chain.QueryProof(host.KeyConnection(connectionID))
proof, height := counterparty.QueryProof(host.KeyChannel(counterpartyCh.PortID, counterpartyCh.ID))
msg := channeltypes.NewMsgChannelOpenConfirm(
ch.PortID, ch.ChannelID,
ch.PortID, ch.ID,
proof, height,
chain.SenderAccount.GetAddress(),
)
return chain.SendMsg(msg)
}
// ChanCloseInit will construct and execute a MsgChannelCloseInit.
//
// NOTE: does not work with ibc-transfer module
func (chain *TestChain) ChanCloseInit(
counterparty *TestChain,
channel TestChannel,
) error {
msg := channeltypes.NewMsgChannelCloseInit(
channel.PortID, channel.ID,
chain.SenderAccount.GetAddress(),
)
return chain.SendMsg(msg)
}
// SendPacket simulates sending a packet through the channel keeper. No message needs to be
// passed since this call is made from a module.
func (chain *TestChain) SendPacket(
packet channelexported.PacketI,
) error {
channelCap := chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel())
// no need to send message, acting as a module
err := chain.App.IBCKeeper.ChannelKeeper.SendPacket(chain.GetContext(), channelCap, packet)
if err != nil {
return err
}
// commit changes
chain.App.Commit()
chain.NextBlock()
return nil
}
// PacketExecuted simulates receiving and wiritng an acknowledgement to the chain.
func (chain *TestChain) PacketExecuted(
packet channelexported.PacketI,
) error {
channelCap := chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel())
// no need to send message, acting as a handler
err := chain.App.IBCKeeper.ChannelKeeper.PacketExecuted(chain.GetContext(), channelCap, packet, TestHash)
if err != nil {
return err
}
// commit changes
chain.App.Commit()
chain.NextBlock()
return nil
}

View File

@ -2,6 +2,7 @@ package testing
import (
"fmt"
"strconv"
"testing"
"time"
@ -9,7 +10,7 @@ import (
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"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
@ -32,7 +33,7 @@ func NewCoordinator(t *testing.T, n int) *Coordinator {
chains := make(map[string]*TestChain)
for i := 0; i < n; i++ {
chainID := ChainIDPrefix + string(i)
chainID := GetChainID(i)
chains[chainID] = NewTestChain(t, chainID)
}
return &Coordinator{
@ -41,60 +42,57 @@ func NewCoordinator(t *testing.T, n int) *Coordinator {
}
}
// 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)),
}
}
// Setup constructs a TM client, connection, and channel on both chains provided. It will
// fails if any error occurs. The clientID's, TestConnections, and TestChannels are returned
// for both chains.
func (coord *Coordinator) Setup(
chainA, chainB *TestChain,
) (string, string, *TestConnection, *TestConnection, TestChannel, TestChannel) {
clientA, clientB, connA, connB := coord.SetupClientConnections(chainA, chainB, clientexported.Tendermint)
// channels can also be referenced through the returned connections
channelA, channelB := coord.CreateChannel(chainA, chainB, connA, connB, channeltypes.UNORDERED)
return clientA, clientB, connA, connB, channelA, channelB
}
// 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
// SetupClients is a helper function to create clients on both chains. It assumes the
// caller does not anticipate any errors.
func (coord *Coordinator) SetupClients(
chainA, chainB *TestChain,
clientType clientexported.ClientType,
) (string, string) {
clientA, err := coord.CreateClient(chainA, chainB, clientType)
require.NoError(coord.t, err)
clientB, err := coord.CreateClient(chainB, chainA, clientType)
require.NoError(coord.t, err)
return clientA, clientB
}
// 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()
}
// SetupClientConnections is a helper function to create clients and the appropriate
// connections on both the source and counterparty chain. It assumes the caller does not
// anticipate any errors.
func (coord *Coordinator) SetupClientConnections(
chainA, chainB *TestChain,
clientType clientexported.ClientType,
) (string, string, *TestConnection, *TestConnection) {
// 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)
clientA, clientB := coord.SetupClients(chainA, chainB, clientType)
for i := uint64(0); i < n; i++ {
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
chain.App.Commit()
chain.NextBlock()
coord.IncrementTime()
}
connA, connB := coord.CreateConnection(chainA, chainB, clientA, clientB)
return clientA, clientB, connA, connB
}
// CreateClient creates a counterparty client on the source chain and returns the clientID.
func (coord *Coordinator) CreateClient(
sourceID, counterpartyID string,
source, counterparty *TestChain,
clientType clientexported.ClientType,
) (clientID string, err error) {
coord.CommitBlock(sourceID, counterpartyID)
source := coord.GetChain(sourceID)
counterparty := coord.GetChain(counterpartyID)
coord.CommitBlock(source, counterparty)
clientID = source.NewClientID(counterparty.ChainID)
@ -117,14 +115,11 @@ func (coord *Coordinator) CreateClient(
// UpdateClient updates a counterparty client on the source chain.
func (coord *Coordinator) UpdateClient(
sourceID, counterpartyID,
source, counterparty *TestChain,
clientID string,
clientType clientexported.ClientType,
) (err error) {
coord.CommitBlock(sourceID, counterpartyID)
source := coord.GetChain(sourceID)
counterparty := coord.GetChain(counterpartyID)
coord.CommitBlock(source, counterparty)
switch clientType {
case clientexported.Tendermint:
@ -144,58 +139,69 @@ func (coord *Coordinator) UpdateClient(
}
// 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.
// OPEN channels on chainA and chainB. The connection information of for chainA and chainB
// are returned within a TestConnection struct. The function expects the connections to be
// successfully opened otherwise testing will fail.
func (coord *Coordinator) CreateConnection(
sourceID, counterpartyID,
clientID, counterpartyClientID string,
state connectiontypes.State,
) (TestConnection, TestConnection, error) {
source := coord.GetChain(sourceID)
counterparty := coord.GetChain(counterpartyID)
chainA, chainB *TestChain,
clientA, clientB string,
) (*TestConnection, *TestConnection) {
sourceConnection := source.NewTestConnection(clientID, counterpartyClientID)
counterpartyConnection := counterparty.NewTestConnection(counterpartyClientID, clientID)
connA, connB, err := coord.ConnOpenInit(chainA, chainB, clientA, clientB)
require.NoError(coord.t, err)
if err := coord.CreateConnectionInit(source, counterparty, sourceConnection, counterpartyConnection); err != nil {
return sourceConnection, counterpartyConnection, err
}
err = coord.ConnOpenTry(chainB, chainA, connB, connA)
require.NoError(coord.t, err)
if err := coord.CreateConnectionOpenTry(counterparty, source, counterpartyConnection, sourceConnection); err != nil {
return sourceConnection, counterpartyConnection, err
}
err = coord.ConnOpenAck(chainA, chainB, connA, connB)
require.NoError(coord.t, err)
if err := coord.CreateConnectionOpenAck(source, counterparty, sourceConnection, counterpartyConnection); err != nil {
return sourceConnection, counterpartyConnection, err
}
err = coord.ConnOpenConfirm(chainB, chainA, connB, connA)
require.NoError(coord.t, err)
if err := coord.CreateConnectionOpenConfirm(counterparty, source, counterpartyConnection, sourceConnection); err != nil {
return sourceConnection, counterpartyConnection, err
}
return sourceConnection, counterpartyConnection, nil
return connA, connB
}
// CreateConenctionInit initializes a connection on the source chain with the state INIT
// using the OpenInit handshake call.
func (coord *Coordinator) CreateConnectionInit(
// CreateChannel constructs and executes channel handshake messages in order to create
// OPEN channels on chainA and chainB. The function expects the channels to be successfully
// opened otherwise testing will fail.
func (coord *Coordinator) CreateChannel(
chainA, chainB *TestChain,
connA, connB *TestConnection,
order channeltypes.Order,
) (TestChannel, TestChannel) {
channelA, channelB, err := coord.ChanOpenInit(chainA, chainB, connA, connB, order)
require.NoError(coord.t, err)
err = coord.ChanOpenTry(chainB, chainA, channelB, channelA, connB, order)
require.NoError(coord.t, err)
err = coord.ChanOpenAck(chainA, chainB, channelA, channelB)
require.NoError(coord.t, err)
err = coord.ChanOpenConfirm(chainB, chainA, channelB, channelA)
require.NoError(coord.t, err)
return channelA, channelB
}
// SendPacket sends a packet through the channel keeper on the source chain and updates the
// counterparty client for the source chain.
func (coord *Coordinator) SendPacket(
source, counterparty *TestChain,
sourceConnection, counterpartyConnection TestConnection,
packet channelexported.PacketI,
counterpartyClientID string,
) error {
// initialize connection on source
if err := source.ConnectionOpenInit(counterparty, sourceConnection, counterpartyConnection); err != nil {
if err := source.SendPacket(packet); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty.ChainID, source.ChainID,
counterpartyConnection.ClientID, clientexported.Tendermint,
counterparty, source,
counterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
}
@ -203,11 +209,108 @@ func (coord *Coordinator) CreateConnectionInit(
return nil
}
// CreateConenctionOpenTry initializes a connection on the source chain with the state TRYOPEN
// using the OpenTry handshake call.
func (coord *Coordinator) CreateConnectionOpenTry(
// PacketExecuted receives a packet through the channel keeper on the source chain and updates the
// counterparty client for the source chain.
func (coord *Coordinator) PacketExecuted(
source, counterparty *TestChain,
sourceConnection, counterpartyConnection TestConnection,
packet channelexported.PacketI,
counterpartyClientID string,
) error {
if err := source.PacketExecuted(packet); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty, source,
counterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
}
return nil
}
// 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.Time = chain.CurrentHeader.Time.Add(timeIncrement)
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
}
}
// 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
}
// GetChainID returns the chainID used for the provided index.
func GetChainID(index int) string {
return ChainIDPrefix + strconv.Itoa(index)
}
// 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 ...*TestChain) {
for _, chain := range chains {
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(chain *TestChain, n uint64) {
for i := uint64(0); i < n; i++ {
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
chain.App.Commit()
chain.NextBlock()
coord.IncrementTime()
}
}
// ConnOpenInit initializes a connection on the source chain with the state INIT
// using the OpenInit handshake call.
//
// NOTE: The counterparty testing connection will be created even if it is not created in the
// application state.
func (coord *Coordinator) ConnOpenInit(
source, counterparty *TestChain,
clientID, counterpartyClientID string,
) (*TestConnection, *TestConnection, error) {
sourceConnection := source.NewTestConnection(clientID, counterpartyClientID)
counterpartyConnection := counterparty.NewTestConnection(counterpartyClientID, clientID)
// initialize connection on source
if err := source.ConnectionOpenInit(counterparty, sourceConnection, counterpartyConnection); err != nil {
return sourceConnection, counterpartyConnection, err
}
coord.IncrementTime()
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty, source,
counterpartyClientID, clientexported.Tendermint,
); err != nil {
return sourceConnection, counterpartyConnection, err
}
return sourceConnection, counterpartyConnection, nil
}
// ConnOpenTry initializes a connection on the source chain with the state TRYOPEN
// using the OpenTry handshake call.
func (coord *Coordinator) ConnOpenTry(
source, counterparty *TestChain,
sourceConnection, counterpartyConnection *TestConnection,
) error {
// initialize TRYOPEN connection on source
if err := source.ConnectionOpenTry(counterparty, sourceConnection, counterpartyConnection); err != nil {
@ -217,7 +320,7 @@ func (coord *Coordinator) CreateConnectionOpenTry(
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty.ChainID, source.ChainID,
counterparty, source,
counterpartyConnection.ClientID, clientexported.Tendermint,
); err != nil {
return err
@ -226,11 +329,11 @@ func (coord *Coordinator) CreateConnectionOpenTry(
return nil
}
// CreateConnectionOpenAck initializes a connection on the source chain with the state OPEN
// ConnOpenAck initializes a connection on the source chain with the state OPEN
// using the OpenAck handshake call.
func (coord *Coordinator) CreateConnectionOpenAck(
func (coord *Coordinator) ConnOpenAck(
source, counterparty *TestChain,
sourceConnection, counterpartyConnection TestConnection,
sourceConnection, counterpartyConnection *TestConnection,
) error {
// set OPEN connection on source using OpenAck
if err := source.ConnectionOpenAck(counterparty, sourceConnection, counterpartyConnection); err != nil {
@ -240,7 +343,7 @@ func (coord *Coordinator) CreateConnectionOpenAck(
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty.ChainID, source.ChainID,
counterparty, source,
counterpartyConnection.ClientID, clientexported.Tendermint,
); err != nil {
return err
@ -249,21 +352,21 @@ func (coord *Coordinator) CreateConnectionOpenAck(
return nil
}
// CreateConnectionOpenConfirm initializes a connection on the source chain with the state OPEN
// ConnOpenConfirm initializes a connection on the source chain with the state OPEN
// using the OpenConfirm handshake call.
func (coord *Coordinator) CreateConnectionOpenConfirm(
func (coord *Coordinator) ConnOpenConfirm(
source, counterparty *TestChain,
sourceConnection, counterpartyConnection TestConnection,
sourceConnection, counterpartyConnection *TestConnection,
) error {
if err := counterparty.ConnectionOpenConfirm(counterparty, sourceConnection, counterpartyConnection); err != nil {
if err := source.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,
counterparty, source,
counterpartyConnection.ClientID, clientexported.Tendermint,
); err != nil {
return err
}
@ -271,87 +374,58 @@ func (coord *Coordinator) CreateConnectionOpenConfirm(
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.
// ChanOpenInit initializes a channel on the source chain with the state INIT
// using the OpenInit handshake call.
//
// 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,
func (coord *Coordinator) ChanOpenInit(
source, counterparty *TestChain,
connection, counterpartyConnection *TestConnection,
order channeltypes.Order,
state channeltypes.State,
) (TestChannel, TestChannel, error) {
source := coord.GetChain(sourceID)
counterparty := coord.GetChain(counterpartyID)
sourceChannel := connection.AddTestChannel()
counterpartyChannel := counterpartyConnection.AddTestChannel()
sourceChannel := source.NewTestChannel()
counterpartyChannel := counterparty.NewTestChannel()
// create port capability
source.CreatePortCapability(sourceChannel.PortID)
coord.IncrementTime()
if err := coord.CreateChannelInit(source, counterparty, sourceChannel, counterpartyChannel, connection, order); err != nil {
// initialize channel on source
if err := source.ChanOpenInit(sourceChannel, counterpartyChannel, order, connection.ID); err != nil {
return sourceChannel, counterpartyChannel, err
}
coord.IncrementTime()
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 {
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty, source,
counterpartyConnection.ClientID, clientexported.Tendermint,
); 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
// ChanOpenTry initializes a channel on the source chain with the state TRYOPEN
// using the OpenTry handshake call.
func (coord *Coordinator) CreateChannelOpenTry(
func (coord *Coordinator) ChanOpenTry(
source, counterparty *TestChain,
sourceChannel, counterpartyChannel TestChannel,
connection TestConnection,
connection *TestConnection,
order channeltypes.Order,
) error {
// initialize channel on source
if err := source.ChannelOpenTry(sourceChannel, counterpartyChannel, order, connection.ID); err != nil {
if err := source.ChanOpenTry(counterparty, 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,
counterparty, source,
connection.CounterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
@ -360,24 +434,22 @@ func (coord *Coordinator) CreateChannelOpenTry(
return nil
}
// CreateChannelOpenAck initializes a channel on the source chain with the state OPEN
// ChanOpenAck initializes a channel on the source chain with the state OPEN
// using the OpenAck handshake call.
func (coord *Coordinator) CreateChannelOpenAck(
func (coord *Coordinator) ChanOpenAck(
source, counterparty *TestChain,
sourceChannel, counterpartyChannel TestChannel,
connection TestConnection,
) error {
// initialize channel on source
if err := source.ChannelOpenAck(sourceChannel, counterpartyChannel, connection.ID); err != nil {
if err := source.ChanOpenAck(counterparty, sourceChannel, counterpartyChannel); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty.ChainID, source.ChainID,
connection.CounterpartyClientID, clientexported.Tendermint,
counterparty, source,
sourceChannel.CounterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
}
@ -385,24 +457,70 @@ func (coord *Coordinator) CreateChannelOpenAck(
return nil
}
// CreateChannelOpenConfirm initializes a channel on the source chain with the state OPEN
// ChanOpenConfirm initializes a channel on the source chain with the state OPEN
// using the OpenConfirm handshake call.
func (coord *Coordinator) CreateChannelOpenConfirm(
func (coord *Coordinator) ChanOpenConfirm(
source, counterparty *TestChain,
sourceChannel, counterpartyChannel TestChannel,
connection TestConnection,
) error {
// initialize channel on source
if err := source.ChannelOpenConfirm(sourceChannel, counterpartyChannel, connection.ID); err != nil {
if err := source.ChanOpenConfirm(counterparty, sourceChannel, counterpartyChannel); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty.ChainID, source.ChainID,
connection.CounterpartyClientID, clientexported.Tendermint,
counterparty, source,
sourceChannel.CounterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
}
return nil
}
// ChanCloseInit closes a channel on the source chain resulting in the channels state
// being set to CLOSED.
//
// NOTE: does not work with ibc-transfer module
func (coord *Coordinator) ChanCloseInit(
source, counterparty *TestChain,
channel TestChannel,
) error {
if err := source.ChanCloseInit(counterparty, channel); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty, source,
channel.CounterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
}
return nil
}
// SetChannelClosed sets a channel state to CLOSED.
func (coord *Coordinator) SetChannelClosed(
source, counterparty *TestChain,
testChannel TestChannel,
) error {
channel := source.GetChannel(testChannel)
channel.State = channeltypes.CLOSED
source.App.IBCKeeper.ChannelKeeper.SetChannel(source.GetContext(), testChannel.PortID, testChannel.ID, channel)
coord.CommitBlock(source)
// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty, source,
testChannel.CounterpartyClientID, clientexported.Tendermint,
); err != nil {
return err
}

View File

@ -1,16 +1,62 @@
package testing
import (
"fmt"
)
// 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
Channels []TestChannel
}
// AddTestChannel appends a new TestChannel which contains references to the port and channel ID
// used for channel creation and interaction.
//
// channel ID format: connectionid-<channel-index>
// the port is set to "transfer" to be compatible with the ICS-transfer module, this should
// eventually be updated as described in the issue: https://github.com/cosmos/cosmos-sdk/issues/6509
func (conn *TestConnection) AddTestChannel() TestChannel {
channel := conn.NextTestChannel()
conn.Channels = append(conn.Channels, channel)
return channel
}
// NextTestChannel returns the next test channel to be created on this connection, but does not
// add it to the list of created channels. This function is expected to be used when the caller
// has not created the associated channel in app state, but would still like to refer to the
// non-existent channel usually to test for its non-existence.
func (conn *TestConnection) NextTestChannel() TestChannel {
portID := "transfer"
channelID := fmt.Sprintf("%s-%d", conn.ID, len(conn.Channels))
return TestChannel{
PortID: portID,
ID: channelID,
ClientID: conn.ClientID,
CounterpartyClientID: conn.CounterpartyClientID,
}
}
// FirstOrNextTestChannel returns the first test channel if it exists, otherwise it
// returns the next test channel to be created. This function is expected to be used
// when the caller does not know if the channel has or has not been created in app
// state, but would still like to refer to it to test existence or non-existence.
func (conn *TestConnection) FirstOrNextTestChannel() TestChannel {
if len(conn.Channels) > 0 {
return conn.Channels[0]
}
return conn.NextTestChannel()
}
// TestChannel is a testing helper struct to keep track of the portID and channelID
// used in creating and interacting with a channel.
// used in creating and interacting with a channel. The clientID and counterparty
// client ID are also tracked to cut down on querying and argument passing.
type TestChannel struct {
PortID string
ChannelID string
PortID string
ID string
ClientID string
CounterpartyClientID string
}