Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICS-02: Keeper Tests #5329

Merged
merged 2 commits into from
Nov 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
}
}