Skip to content

Commit

Permalink
ICS-02: Keeper Tests (#5329)
Browse files Browse the repository at this point in the history
* add keeper tests

* fix tendermint tests
  • Loading branch information
AdityaSripal authored and fedekunze committed Nov 19, 2019
1 parent 2de199f commit 6cd6d4f
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 47 deletions.
113 changes: 113 additions & 0 deletions x/ibc/02-client/keeper/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package keeper_test

import (
"fmt"

"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint"
commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment"
"github.com/stretchr/testify/require"
tmtypes "github.com/tendermint/tendermint/types"
)

const (
testClientType exported.ClientType = iota + 2
)

func (suite *KeeperTestSuite) TestCreateClient() {
// Test Valid CreateClient
state, err := suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState)
require.Nil(suite.T(), err, "CreateClient failed")

// Test ClientState stored correctly
expectedState := types.State{
ID: testClientID,
Frozen: false,
}
require.Equal(suite.T(), expectedState, state, "Incorrect ClientState returned")

// Test ClientType and VerifiedRoot stored correctly
clientType, _ := suite.keeper.GetClientType(suite.ctx, testClientID)
require.Equal(suite.T(), exported.Tendermint, clientType, "Incorrect ClientType stored")
root, _ := suite.keeper.GetVerifiedRoot(suite.ctx, testClientID, suite.consensusState.GetHeight())
require.Equal(suite.T(), suite.consensusState.GetRoot(), root, "Incorrect root stored")

// Test that trying to CreateClient on existing client fails
_, err = suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState)
require.NotNil(suite.T(), err, "CreateClient on existing client: %s passed", testClientID)
}

func (suite *KeeperTestSuite) TestUpdateClient() {
privVal := tmtypes.NewMockPV()
validator := tmtypes.NewValidator(privVal.GetPubKey(), 1)
altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
altSigners := []tmtypes.PrivValidator{privVal}

// Test invalid cases all fail and do not update state
cases := []struct {
name string
malleate func()
expErr bool
}{
{"valid update", func() {}, false},
{"wrong client type", func() {
suite.keeper.SetClientType(suite.ctx, testClientID, testClientType)
}, true},
{"frozen client", func() {
clientState, _ := suite.keeper.GetClientState(suite.ctx, testClientID)
clientState.Frozen = true
suite.keeper.SetClientState(suite.ctx, clientState)
}, true},
{"past height", func() {
suite.header = tendermint.MakeHeader(2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
}, true},
{"validatorHash incorrect", func() {
suite.header = tendermint.MakeHeader(4, altValSet, suite.valSet, altSigners)
}, true},
{"nextHash incorrect", func() {
suite.header.NextValidatorSet = altValSet
}, true},
{"header fails validateBasic", func() {
suite.header.ChainID = "test"
}, true},
{"verify future commit fails", func() {
suite.consensusState.NextValidatorSet = altValSet
suite.keeper.SetConsensusState(suite.ctx, testClientID, suite.consensusState)
}, true},
}

for _, tc := range cases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
// Reset suite on each subtest
suite.SetupTest()

_, err := suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState)
require.Nil(suite.T(), err, "CreateClient failed")

tc.malleate()
err = suite.keeper.UpdateClient(suite.ctx, testClientID, suite.header)

retrievedConsState, _ := suite.keeper.GetConsensusState(suite.ctx, testClientID)
tmConsState, _ := retrievedConsState.(tendermint.ConsensusState)
tmConsState.NextValidatorSet.TotalVotingPower()
retrievedRoot, _ := suite.keeper.GetVerifiedRoot(suite.ctx, testClientID, suite.consensusState.GetHeight()+1)
if tc.expErr {
require.NotNil(suite.T(), err, "Invalid UpdateClient passed", tc.name)

// require no state changes occurred
require.Equal(suite.T(), suite.consensusState, tmConsState, "Consensus state changed after invalid UpdateClient")
require.Nil(suite.T(), retrievedRoot, "Root added for new height after invalid UpdateClient")
} else {
require.Nil(suite.T(), err, "Valid UpdateClient failed", tc.name)

// require state changes were performed correctly
require.Equal(suite.T(), suite.header.GetHeight(), retrievedConsState.GetHeight(), "height not updated correctly")
require.Equal(suite.T(), commitment.NewRoot(suite.header.AppHash), retrievedConsState.GetRoot(), "root not updated correctly")
require.Equal(suite.T(), suite.header.NextValidatorSet, tmConsState.NextValidatorSet, "NextValidatorSet not updated correctly")

}

})
}
}
102 changes: 102 additions & 0 deletions x/ibc/02-client/keeper/keeper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package keeper_test

import (
"testing"

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"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint"
commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)

const (
testClientID = "gaia"
)

type KeeperTestSuite struct {
suite.Suite

cdc *codec.Codec
ctx sdk.Context
keeper *keeper.Keeper
consensusState tendermint.ConsensusState
header tendermint.Header
valSet *tmtypes.ValidatorSet
privVal tmtypes.PrivValidator
}

func (suite *KeeperTestSuite) SetupTest() {
isCheckTx := false
app := simapp.Setup(isCheckTx)

suite.cdc = app.Codec()
suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{})
suite.keeper = &app.IBCKeeper.ClientKeeper

suite.privVal = tmtypes.NewMockPV()

validator := tmtypes.NewValidator(suite.privVal.GetPubKey(), 1)
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})

suite.header = tendermint.MakeHeader(4, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})

suite.consensusState = tendermint.ConsensusState{
ChainID: testClientID,
Height: 3,
Root: commitment.NewRoot([]byte("hash")),
NextValidatorSet: suite.valSet,
}
}

func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

func (suite *KeeperTestSuite) TestSetClientState() {
clientState := types.NewClientState(testClientID)
suite.keeper.SetClientState(suite.ctx, clientState)

retrievedState, ok := suite.keeper.GetClientState(suite.ctx, testClientID)
require.True(suite.T(), ok, "GetClientState failed")
require.Equal(suite.T(), clientState, retrievedState, "Client states are not equal")
}

func (suite *KeeperTestSuite) TestSetClientType() {
suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint)
clientType, ok := suite.keeper.GetClientType(suite.ctx, testClientID)

require.True(suite.T(), ok, "GetClientType failed")
require.Equal(suite.T(), exported.Tendermint, clientType, "ClientTypes not stored correctly")
}

func (suite *KeeperTestSuite) TestSetConsensusState() {
suite.keeper.SetConsensusState(suite.ctx, testClientID, suite.consensusState)

retrievedConsState, ok := suite.keeper.GetConsensusState(suite.ctx, testClientID)

require.True(suite.T(), ok, "GetConsensusState failed")
tmConsState, _ := retrievedConsState.(tendermint.ConsensusState)
// force recalculation of unexported totalVotingPower so we can compare consensusState
tmConsState.NextValidatorSet.TotalVotingPower()
require.Equal(suite.T(), suite.consensusState, tmConsState, "ConsensusState not stored correctly")
}

func (suite *KeeperTestSuite) TestSetVerifiedRoot() {
root := commitment.NewRoot([]byte("hash"))
suite.keeper.SetVerifiedRoot(suite.ctx, testClientID, 3, root)

retrievedRoot, ok := suite.keeper.GetVerifiedRoot(suite.ctx, testClientID, 3)

require.True(suite.T(), ok, "GetVerifiedRoot failed")
require.Equal(suite.T(), root, retrievedRoot, "Root stored incorrectly")
}
4 changes: 2 additions & 2 deletions x/ibc/02-client/types/tendermint/consensus_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {

// reset and make header fail validatebasic
suite.SetupTest()
suite.header.ChainID = "not_mychain"
suite.header.ChainID = "not_gaia"
err = suite.cs.checkValidity(suite.header)
require.NotNil(suite.T(), err, "invalid header should fail ValidateBasic")
}
Expand All @@ -44,7 +44,7 @@ func (suite *TendermintTestSuite) TestCheckUpdate() {

// make header invalid so update should be unsuccessful
suite.SetupTest()
suite.header.ChainID = "not_mychain"
suite.header.ChainID = "not_gaia"

cs, err = suite.cs.CheckValidityAndUpdateState(suite.header)
require.NotNil(suite.T(), err)
Expand Down
46 changes: 2 additions & 44 deletions x/ibc/02-client/types/tendermint/tendermint_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package tendermint

import (
"math"
"testing"
"time"

"github.com/stretchr/testify/suite"

"github.com/tendermint/tendermint/crypto/tmhash"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"

commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment"
)
Expand All @@ -27,49 +24,11 @@ func (suite *TendermintTestSuite) SetupTest() {
privVal := tmtypes.NewMockPV()
val := tmtypes.NewValidator(privVal.GetPubKey(), 10)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
vsetHash := valSet.Hash()
timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
tmHeader := tmtypes.Header{
Version: version.Consensus{Block: 2, App: 2},
ChainID: "mychain",
Height: 3,
Time: timestamp,
NumTxs: 100,
TotalTxs: 1000,
LastBlockID: makeBlockID(make([]byte, tmhash.Size), math.MaxInt64, make([]byte, tmhash.Size)),
LastCommitHash: tmhash.Sum([]byte("last_commit_hash")),
DataHash: tmhash.Sum([]byte("data_hash")),
ValidatorsHash: vsetHash,
NextValidatorsHash: vsetHash,
ConsensusHash: tmhash.Sum([]byte("consensus_hash")),
AppHash: tmhash.Sum([]byte("app_hash")),
LastResultsHash: tmhash.Sum([]byte("last_results_hash")),
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: privVal.GetPubKey().Address(),
}
hhash := tmHeader.Hash()
blockID := makeBlockID(hhash, 3, tmhash.Sum([]byte("part_set")))
voteSet := tmtypes.NewVoteSet("mychain", 3, 1, tmtypes.PrecommitType, valSet)
commit, err := tmtypes.MakeCommit(blockID, 3, 1, voteSet, []tmtypes.PrivValidator{privVal})
if err != nil {
panic(err)
}

signedHeader := tmtypes.SignedHeader{
Header: &tmHeader,
Commit: commit,
}

header := Header{
SignedHeader: signedHeader,
ValidatorSet: valSet,
NextValidatorSet: valSet,
}

suite.header = MakeHeader(3, valSet, valSet, []tmtypes.PrivValidator{privVal})
root := commitment.NewRoot(tmhash.Sum([]byte("my root")))

cs := ConsensusState{
ChainID: "mychain",
ChainID: "gaia",
Height: 3,
Root: root,
NextValidatorSet: valSet,
Expand All @@ -78,7 +37,6 @@ func (suite *TendermintTestSuite) SetupTest() {
// set fields in suite
suite.privVal = privVal
suite.valSet = valSet
suite.header = header
suite.cs = cs
}

Expand Down
48 changes: 47 additions & 1 deletion x/ibc/02-client/types/tendermint/test_utils.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package tendermint

import (
"math"
"time"

"github.com/tendermint/tendermint/crypto/tmhash"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
)

// Copied unimported test functions from tmtypes to use them here
Expand Down Expand Up @@ -38,10 +42,52 @@ func randomDuplicatedVoteEvidence() *tmtypes.DuplicateVoteEvidence {
val := tmtypes.NewMockPV()
blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), 1000, tmhash.Sum([]byte("partshash")))
blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), 1000, tmhash.Sum([]byte("partshash")))
const chainID = "mychain"
const chainID = "gaia"
return &tmtypes.DuplicateVoteEvidence{
PubKey: val.GetPubKey(),
VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID),
VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2),
}
}

func MakeHeader(height int64, valSet *tmtypes.ValidatorSet, nextValSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) Header {
vsetHash := valSet.Hash()
nextHash := nextValSet.Hash()
timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
tmHeader := tmtypes.Header{
Version: version.Consensus{Block: 2, App: 2},
ChainID: "gaia",
Height: height,
Time: timestamp,
NumTxs: 100,
TotalTxs: 1000,
LastBlockID: makeBlockID(make([]byte, tmhash.Size), math.MaxInt64, make([]byte, tmhash.Size)),
LastCommitHash: tmhash.Sum([]byte("last_commit_hash")),
DataHash: tmhash.Sum([]byte("data_hash")),
ValidatorsHash: vsetHash,
NextValidatorsHash: nextHash,
ConsensusHash: tmhash.Sum([]byte("consensus_hash")),
AppHash: tmhash.Sum([]byte("app_hash")),
LastResultsHash: tmhash.Sum([]byte("last_results_hash")),
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: signers[0].GetPubKey().Address(),
}
hhash := tmHeader.Hash()
blockID := makeBlockID(hhash, 3, tmhash.Sum([]byte("part_set")))
voteSet := tmtypes.NewVoteSet("gaia", height, 1, tmtypes.PrecommitType, valSet)
commit, err := tmtypes.MakeCommit(blockID, height, 1, voteSet, signers)
if err != nil {
panic(err)
}

signedHeader := tmtypes.SignedHeader{
Header: &tmHeader,
Commit: commit,
}

return Header{
SignedHeader: signedHeader,
ValidatorSet: valSet,
NextValidatorSet: nextValSet,
}
}

0 comments on commit 6cd6d4f

Please sign in to comment.