cosmos-sdk/x/ibc/02-client/keeper/keeper_test.go

232 lines
8.5 KiB
Go

package keeper_test
import (
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
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/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
testClientID = "gaia"
testClientID2 = "ethbridge"
testClientID3 = "ethermint"
testClientHeight = 5
trustingPeriod time.Duration = time.Hour * 24 * 7 * 2
ubdPeriod time.Duration = time.Hour * 24 * 7 * 3
maxClockDrift time.Duration = time.Second * 10
)
type KeeperTestSuite struct {
suite.Suite
cdc *codec.Codec
ctx sdk.Context
keeper *keeper.Keeper
consensusState ibctmtypes.ConsensusState
header ibctmtypes.Header
valSet *tmtypes.ValidatorSet
privVal tmtypes.PrivValidator
now time.Time
}
func (suite *KeeperTestSuite) SetupTest() {
isCheckTx := false
suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
now2 := suite.now.Add(time.Hour)
app := simapp.Setup(isCheckTx)
suite.cdc = app.Codec()
suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{Height: testClientHeight, ChainID: testClientID, Time: now2})
suite.keeper = &app.IBCKeeper.ClientKeeper
suite.privVal = tmtypes.NewMockPV()
pubKey, err := suite.privVal.GetPubKey()
suite.Require().NoError(err)
validator := tmtypes.NewValidator(pubKey, 1)
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
suite.header = ibctmtypes.CreateTestHeader(testClientID, testClientHeight, now2, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
suite.consensusState = ibctmtypes.ConsensusState{
Height: testClientHeight,
Timestamp: suite.now,
Root: commitmenttypes.NewMerkleRoot([]byte("hash")),
ValidatorSet: suite.valSet,
}
var validators staking.Validators
for i := 1; i < 11; i++ {
privVal := tmtypes.NewMockPV()
pk, err := privVal.GetPubKey()
suite.Require().NoError(err)
val := staking.NewValidator(sdk.ValAddress(pk.Address()), pk, staking.Description{})
val.Status = sdk.Bonded
val.Tokens = sdk.NewInt(rand.Int63())
validators = append(validators, val)
app.StakingKeeper.SetHistoricalInfo(suite.ctx, int64(i), staking.NewHistoricalInfo(suite.ctx.BlockHeader(), validators))
}
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func (suite *KeeperTestSuite) TestSetClientState() {
clientState := ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{})
suite.keeper.SetClientState(suite.ctx, clientState)
retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
suite.Require().True(found, "GetClientState failed")
suite.Require().Equal(clientState, retrievedState, "Client states are not equal")
}
func (suite *KeeperTestSuite) TestSetClientType() {
suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint)
clientType, found := suite.keeper.GetClientType(suite.ctx, testClientID)
suite.Require().True(found, "GetClientType failed")
suite.Require().Equal(exported.Tendermint, clientType, "ClientTypes not stored correctly")
}
func (suite *KeeperTestSuite) TestSetClientConsensusState() {
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
retrievedConsState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, testClientHeight)
suite.Require().True(found, "GetConsensusState failed")
tmConsState, ok := retrievedConsState.(ibctmtypes.ConsensusState)
// recalculate cached totalVotingPower field for equality check
tmConsState.ValidatorSet.TotalVotingPower()
suite.Require().True(ok)
suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly")
}
func (suite KeeperTestSuite) TestGetAllClients() {
expClients := []exported.ClientState{
ibctmtypes.NewClientState(testClientID2, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
ibctmtypes.NewClientState(testClientID3, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
}
for i := range expClients {
suite.keeper.SetClientState(suite.ctx, expClients[i])
}
clients := suite.keeper.GetAllClients(suite.ctx)
suite.Require().Len(clients, len(expClients))
suite.Require().Equal(expClients, clients)
}
func (suite KeeperTestSuite) TestGetConsensusState() {
suite.ctx = suite.ctx.WithBlockHeight(10)
cases := []struct {
name string
height uint64
expPass bool
}{
{"zero height", 0, false},
{"height > latest height", uint64(suite.ctx.BlockHeight()) + 1, false},
{"latest height - 1", uint64(suite.ctx.BlockHeight()) - 1, true},
{"latest height", uint64(suite.ctx.BlockHeight()), true},
}
for i, tc := range cases {
tc := tc
cs, found := suite.keeper.GetSelfConsensusState(suite.ctx, tc.height)
if tc.expPass {
suite.Require().True(found, "Case %d should have passed: %s", i, tc.name)
suite.Require().NotNil(cs, "Case %d should have passed: %s", i, tc.name)
} else {
suite.Require().False(found, "Case %d should have failed: %s", i, tc.name)
suite.Require().Nil(cs, "Case %d should have failed: %s", i, tc.name)
}
}
}
func (suite KeeperTestSuite) TestConsensusStateHelpers() {
// initial setup
clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
suite.Require().NoError(err)
suite.keeper.SetClientState(suite.ctx, clientState)
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
nextState := ibctmtypes.ConsensusState{
Height: testClientHeight + 5,
Timestamp: suite.now,
Root: commitmenttypes.NewMerkleRoot([]byte("next")),
ValidatorSet: suite.valSet,
}
header := ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.header.Time.Add(time.Minute), suite.valSet, []tmtypes.PrivValidator{suite.privVal})
// mock update functionality
clientState.LastHeader = header
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+5, nextState)
suite.keeper.SetClientState(suite.ctx, clientState)
latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID)
// recalculate cached totalVotingPower for equality check
latest.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower()
suite.Require().True(ok)
suite.Require().Equal(nextState, latest, "Latest client not returned correctly")
// Should return existing consensusState at latestClientHeight
lte, ok := suite.keeper.GetClientConsensusStateLTE(suite.ctx, testClientID, testClientHeight+3)
// recalculate cached totalVotingPower for equality check
lte.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower()
suite.Require().True(ok)
suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", testClientHeight+3)
}
func (suite KeeperTestSuite) TestGetAllConsensusStates() {
expConsensus := []types.ClientConsensusStates{
types.NewClientConsensusStates(
testClientID,
[]exported.ConsensusState{
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.consensusState.GetHeight(), &tmtypes.ValidatorSet{},
),
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp.Add(time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash")), suite.consensusState.GetHeight()+1, &tmtypes.ValidatorSet{},
),
},
),
types.NewClientConsensusStates(
testClientID2,
[]exported.ConsensusState{
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp.Add(2*time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash_2")), suite.consensusState.GetHeight()+2, &tmtypes.ValidatorSet{},
),
},
),
}
for i := range expConsensus {
for _, cons := range expConsensus[i].ConsensusStates {
suite.keeper.SetClientConsensusState(suite.ctx, expConsensus[i].ClientID, cons.GetHeight(), cons)
}
}
consStates := suite.keeper.GetAllConsensusStates(suite.ctx)
suite.Require().Len(consStates, len(expConsensus))
suite.Require().Equal(expConsensus, consStates)
}