package keeper_test import ( "fmt" "testing" "time" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" 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" "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // define constants used for testing const ( testClientIDA = "testclientIDA" testClientIDB = "testClientIDb" testConnection = "testconnectionatob" testPort1 = "bank" testPort2 = "testportid" testChannel1 = "firstchannel" testChannel2 = "secondchannel" trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 maxClockDrift time.Duration = time.Second * 10 ) // define variables used for testing var ( testAddr1, _ = sdk.AccAddressFromBech32("cosmos1scqhwpgsmr6vmztaa7suurfl52my6nd2kmrudl") testAddr2, _ = sdk.AccAddressFromBech32("cosmos1scqhwpgsmr6vmztaa7suurfl52my6nd2kmrujl") testCoins, _ = sdk.ParseCoins("100atom") prefixCoins = sdk.NewCoins(sdk.NewCoin("bank/firstchannel/atom", sdk.NewInt(100))) prefixCoins2 = sdk.NewCoins(sdk.NewCoin("testportid/secondchannel/atom", sdk.NewInt(100))) ) type KeeperTestSuite struct { suite.Suite cdc *codec.Codec chainA *TestChain chainB *TestChain } func (suite *KeeperTestSuite) SetupTest() { suite.chainA = NewTestChain(testClientIDA) suite.chainB = NewTestChain(testClientIDB) // reset prefixCoins at each setup prefixCoins = sdk.NewCoins(sdk.NewCoin("bank/firstchannel/atom", sdk.NewInt(100))) prefixCoins2 = sdk.NewCoins(sdk.NewCoin("testportid/secondchannel/atom", sdk.NewInt(100))) suite.cdc = suite.chainA.App.Codec() } // nolint: unused func (suite *KeeperTestSuite) queryProof(key []byte) (proof commitmenttypes.MerkleProof, height int64) { res := suite.chainA.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", host.StoreKey), Data: key, Prove: true, }) height = res.Height proof = commitmenttypes.MerkleProof{ Proof: res.Proof, } return } func (suite *KeeperTestSuite) TestGetTransferAccount() { expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))) macc := suite.chainA.App.TransferKeeper.GetTransferAccount(suite.chainA.GetContext()) suite.NotNil(macc) suite.Equal(types.ModuleName, macc.GetName()) suite.Equal(expectedMaccAddr, macc.GetAddress()) } func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } 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: chain.Header.SignedHeader.Header.Height}) } // 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: client.Header.SignedHeader.Header.Height, 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, client.Header.SignedHeader.Header.Height, 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, // ) } // nolint: unused 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: client.Header.SignedHeader.Header.Height, 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, client.Header.SignedHeader.Header.Height, 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 channeltypes.State, order channeltypes.Order, connectionID string, ) channeltypes.Channel { counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) channel := channeltypes.NewChannel(state, order, counterparty, []string{connectionID}, "1.0", ) ctx := chain.GetContext() chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) return channel } func nextHeader(chain *TestChain) ibctmtypes.Header { return ibctmtypes.CreateTestHeader(chain.Header.SignedHeader.Header.ChainID, chain.Header.SignedHeader.Header.Height+1, chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers) }