Remove ValidatorSet from ConsensusState (#6942)
* fix stash merge * fix build errors * fix tendermint types test * fix tendermint tests * fix client tests * fix rest of ibc tests * include TrustedHeight in Header * fix all tests * fix all tests * remove validatorshash from consensus state * lint * add evidence checks * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * refix build * remove redundant hashing in tests * complete rest of minor review requests * make format * suite.valsetHash * fix test * Update x/ibc/07-tendermint/misbehaviour.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
This commit is contained in:
parent
04cb1fb05f
commit
e3391ff447
|
@ -5,9 +5,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
proto "github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
proto "github.com/gogo/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ types.UnpackInterfacesMessage = GenesisState{}
|
var _ types.UnpackInterfacesMessage = GenesisState{}
|
||||||
|
|
|
@ -93,7 +93,7 @@ func TestPackAccountsAny(t *testing.T) {
|
||||||
{
|
{
|
||||||
"expected genesis account",
|
"expected genesis account",
|
||||||
func() {
|
func() {
|
||||||
accounts = []*codectypes.Any{&codectypes.Any{}}
|
accounts = []*codectypes.Any{{}}
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,12 +3,13 @@ package evidence
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
|
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
|
||||||
"github.com/cosmos/cosmos-sdk/x/evidence/keeper"
|
"github.com/cosmos/cosmos-sdk/x/evidence/keeper"
|
||||||
"github.com/cosmos/cosmos-sdk/x/evidence/types"
|
"github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitGenesis initializes the evidence module's state from a provided genesis
|
// InitGenesis initializes the evidence module's state from a provided genesis
|
||||||
|
|
|
@ -3,9 +3,10 @@ package types
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
proto "github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
|
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
|
||||||
proto "github.com/gogo/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ types.UnpackInterfacesMessage = GenesisState{}
|
var _ types.UnpackInterfacesMessage = GenesisState{}
|
||||||
|
|
|
@ -105,7 +105,7 @@ func TestGenesisStateValidate(t *testing.T) {
|
||||||
"expected evidence",
|
"expected evidence",
|
||||||
func() {
|
func() {
|
||||||
genesisState = types.GenesisState{
|
genesisState = types.GenesisState{
|
||||||
Evidence: []*codectypes.Any{&codectypes.Any{}},
|
Evidence: []*codectypes.Any{{}},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
|
@ -127,7 +127,7 @@ func TestGenesisStateValidate(t *testing.T) {
|
||||||
|
|
||||||
func TestUnpackInterfaces(t *testing.T) {
|
func TestUnpackInterfaces(t *testing.T) {
|
||||||
var gs = types.GenesisState{
|
var gs = types.GenesisState{
|
||||||
Evidence: []*codectypes.Any{&codectypes.Any{}},
|
Evidence: []*codectypes.Any{{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
|
|
@ -142,15 +142,16 @@ func QueryNodeConsensusState(clientCtx client.Context) (ibctmtypes.ConsensusStat
|
||||||
return ibctmtypes.ConsensusState{}, 0, err
|
return ibctmtypes.ConsensusState{}, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
validators, err := node.Validators(&height, 0, 10000)
|
nextHeight := height + 1
|
||||||
|
nextVals, err := node.Validators(&nextHeight, 0, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ibctmtypes.ConsensusState{}, 0, err
|
return ibctmtypes.ConsensusState{}, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
state := ibctmtypes.ConsensusState{
|
state := ibctmtypes.ConsensusState{
|
||||||
Timestamp: commit.Time,
|
Timestamp: commit.Time,
|
||||||
Root: commitmenttypes.NewMerkleRoot(commit.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(commit.AppHash),
|
||||||
ValidatorSet: tmtypes.NewValidatorSet(validators.Validators),
|
NextValidatorsHash: tmtypes.NewValidatorSet(nextVals.Validators).Hash(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return state, height, nil
|
return state, height, nil
|
||||||
|
|
|
@ -71,9 +71,15 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H
|
||||||
|
|
||||||
switch clientType {
|
switch clientType {
|
||||||
case exported.Tendermint:
|
case exported.Tendermint:
|
||||||
trustedConsState, found := k.GetClientConsensusStateLTE(ctx, clientID, header.GetHeight())
|
tmHeader, ok := header.(ibctmtypes.Header)
|
||||||
|
if !ok {
|
||||||
|
err = sdkerrors.Wrapf(types.ErrInvalidHeader, "expected tendermint header: %T, got header type: %T", ibctmtypes.Header{}, header)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Get the consensus state at the trusted height of header
|
||||||
|
trustedConsState, found := k.GetClientConsensusState(ctx, clientID, tmHeader.TrustedHeight)
|
||||||
if !found {
|
if !found {
|
||||||
return nil, sdkerrors.Wrapf(types.ErrConsensusStateNotFound, "could not find consensus state less than header height: %d to verify header against", header.GetHeight())
|
return nil, sdkerrors.Wrapf(types.ErrConsensusStateNotFound, "could not find consensus state for trusted header height: %d to verify header against for clientID: %s", tmHeader.TrustedHeight, clientID)
|
||||||
}
|
}
|
||||||
clientState, consensusState, err = tendermint.CheckValidityAndUpdateState(
|
clientState, consensusState, err = tendermint.CheckValidityAndUpdateState(
|
||||||
clientState, trustedConsState, header, ctx.BlockTime(),
|
clientState, trustedConsState, header, ctx.BlockTime(),
|
||||||
|
@ -127,14 +133,15 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour ex
|
||||||
return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID())
|
return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID())
|
||||||
}
|
}
|
||||||
|
|
||||||
consensusState, found := k.GetClientConsensusStateLTE(ctx, misbehaviour.GetClientID(), uint64(misbehaviour.GetHeight()))
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrConsensusStateNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID())
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch e := misbehaviour.(type) {
|
switch e := misbehaviour.(type) {
|
||||||
case ibctmtypes.Evidence:
|
case ibctmtypes.Evidence:
|
||||||
|
// Get ConsensusState at TrustedHeight
|
||||||
|
consensusState, found := k.GetClientConsensusState(ctx, misbehaviour.GetClientID(), e.Header1.TrustedHeight)
|
||||||
|
if !found {
|
||||||
|
return sdkerrors.Wrapf(types.ErrConsensusStateNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID())
|
||||||
|
}
|
||||||
|
|
||||||
clientState, err = tendermint.CheckMisbehaviourAndUpdateState(
|
clientState, err = tendermint.CheckMisbehaviourAndUpdateState(
|
||||||
clientState, consensusState, misbehaviour, consensusState.GetHeight(), ctx.BlockTime(), ctx.ConsensusParams(),
|
clientState, consensusState, misbehaviour, consensusState.GetHeight(), ctx.BlockTime(), ctx.ConsensusParams(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -60,12 +60,12 @@ func (suite *KeeperTestSuite) TestCreateClient() {
|
||||||
func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||||
// Must create header creation functions since suite.header gets recreated on each test case
|
// Must create header creation functions since suite.header gets recreated on each test case
|
||||||
createFutureUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
|
createFutureUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
|
||||||
return ibctmtypes.CreateTestHeader(testChainID, suite.header.Height+1, suite.header.Time.Add(time.Minute),
|
return ibctmtypes.CreateTestHeader(testChainID, suite.header.Height+3, suite.header.Height, suite.header.Time.Add(time.Hour),
|
||||||
suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||||
}
|
}
|
||||||
createPastUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
|
createPastUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
|
||||||
return ibctmtypes.CreateTestHeader(testChainID, suite.header.Height-3, suite.header.Time,
|
return ibctmtypes.CreateTestHeader(testChainID, suite.header.Height-2, suite.header.Height-4, suite.header.Time,
|
||||||
suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
updateHeader ibctmtypes.Header
|
updateHeader ibctmtypes.Header
|
||||||
|
@ -80,6 +80,18 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||||
{"valid update", func() error {
|
{"valid update", func() error {
|
||||||
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
||||||
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
||||||
|
|
||||||
|
// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
|
||||||
|
intermediateConsState := ibctmtypes.ConsensusState{
|
||||||
|
Height: testClientHeight + 1,
|
||||||
|
Timestamp: suite.now.Add(time.Minute),
|
||||||
|
NextValidatorsHash: suite.valSetHash,
|
||||||
|
}
|
||||||
|
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+1, intermediateConsState)
|
||||||
|
|
||||||
|
clientState.LatestHeight = testClientHeight + 1
|
||||||
|
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
|
||||||
|
|
||||||
updateHeader = createFutureUpdateFn(suite)
|
updateHeader = createFutureUpdateFn(suite)
|
||||||
return err
|
return err
|
||||||
}, true},
|
}, true},
|
||||||
|
@ -92,11 +104,18 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||||
prevConsState := ibctmtypes.ConsensusState{
|
prevConsState := ibctmtypes.ConsensusState{
|
||||||
Height: 1,
|
Height: 1,
|
||||||
Timestamp: suite.past,
|
Timestamp: suite.past,
|
||||||
NextValidatorsHash: suite.valSet.Hash(),
|
NextValidatorsHash: suite.valSetHash,
|
||||||
ValidatorSet: suite.valSet,
|
|
||||||
}
|
}
|
||||||
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, 1, prevConsState)
|
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, 1, prevConsState)
|
||||||
|
|
||||||
|
// store intermediate consensus state to check that trustedHeight does not need to be hightest consensus state before header height
|
||||||
|
intermediateConsState := ibctmtypes.ConsensusState{
|
||||||
|
Height: 2,
|
||||||
|
Timestamp: suite.past.Add(time.Minute),
|
||||||
|
NextValidatorsHash: suite.valSetHash,
|
||||||
|
}
|
||||||
|
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, 2, intermediateConsState)
|
||||||
|
|
||||||
// updateHeader will fill in consensus state between prevConsState and suite.consState
|
// updateHeader will fill in consensus state between prevConsState and suite.consState
|
||||||
// clientState should not be updated
|
// clientState should not be updated
|
||||||
updateHeader = createPastUpdateFn(suite)
|
updateHeader = createPastUpdateFn(suite)
|
||||||
|
@ -145,8 +164,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||||
prevConsState := ibctmtypes.ConsensusState{
|
prevConsState := ibctmtypes.ConsensusState{
|
||||||
Height: 1,
|
Height: 1,
|
||||||
Timestamp: suite.past,
|
Timestamp: suite.past,
|
||||||
NextValidatorsHash: suite.valSet.Hash(),
|
NextValidatorsHash: suite.valSetHash,
|
||||||
ValidatorSet: suite.valSet,
|
|
||||||
}
|
}
|
||||||
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, 1, prevConsState)
|
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, 1, prevConsState)
|
||||||
|
|
||||||
|
@ -186,7 +204,6 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||||
Timestamp: updateHeader.Time,
|
Timestamp: updateHeader.Time,
|
||||||
Root: commitmenttypes.NewMerkleRoot(updateHeader.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(updateHeader.AppHash),
|
||||||
NextValidatorsHash: updateHeader.NextValidatorsHash,
|
NextValidatorsHash: updateHeader.NextValidatorsHash,
|
||||||
ValidatorSet: updateHeader.ValidatorSet,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newClientState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
|
newClientState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
|
||||||
|
@ -194,11 +211,6 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||||
|
|
||||||
consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, updateHeader.GetHeight())
|
consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, updateHeader.GetHeight())
|
||||||
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
|
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
|
||||||
tmConsState, ok := consensusState.(ibctmtypes.ConsensusState)
|
|
||||||
suite.Require().True(ok, "consensus state is not a tendermint consensus state")
|
|
||||||
// recalculate cached totalVotingPower field for equality check
|
|
||||||
tmConsState.ValidatorSet.TotalVotingPower()
|
|
||||||
|
|
||||||
// check returned client state is same as client state in store
|
// check returned client state is same as client state in store
|
||||||
suite.Require().Equal(updatedClientState, newClientState, "updatedClient state not persisted correctly")
|
suite.Require().Equal(updatedClientState, newClientState, "updatedClient state not persisted correctly")
|
||||||
|
|
||||||
|
@ -263,13 +275,13 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||||
{
|
{
|
||||||
"trusting period misbehavior should pass",
|
"trusting period misbehavior should pass",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: testClientID,
|
ChainID: testClientID,
|
||||||
ClientID: testClientID,
|
ClientID: testClientID,
|
||||||
},
|
},
|
||||||
func() error {
|
func() error {
|
||||||
suite.consensusState.ValidatorSet = bothValSet
|
suite.consensusState.NextValidatorsHash = bothValSet.Hash()
|
||||||
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
||||||
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
||||||
|
|
||||||
|
@ -280,16 +292,27 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||||
{
|
{
|
||||||
"misbehavior at later height should pass",
|
"misbehavior at later height should pass",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: testClientID,
|
ChainID: testClientID,
|
||||||
ClientID: testClientID,
|
ClientID: testClientID,
|
||||||
},
|
},
|
||||||
func() error {
|
func() error {
|
||||||
suite.consensusState.ValidatorSet = bothValSet
|
suite.consensusState.NextValidatorsHash = bothValSet.Hash()
|
||||||
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
||||||
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
||||||
|
|
||||||
|
// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
|
||||||
|
intermediateConsState := ibctmtypes.ConsensusState{
|
||||||
|
Height: testClientHeight + 3,
|
||||||
|
Timestamp: suite.now.Add(time.Minute),
|
||||||
|
NextValidatorsHash: suite.valSetHash,
|
||||||
|
}
|
||||||
|
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+3, intermediateConsState)
|
||||||
|
|
||||||
|
clientState.LatestHeight = testClientHeight + 3
|
||||||
|
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
@ -303,8 +326,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||||
{
|
{
|
||||||
"consensus state not found",
|
"consensus state not found",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: testClientID,
|
ChainID: testClientID,
|
||||||
ClientID: testClientID,
|
ClientID: testClientID,
|
||||||
},
|
},
|
||||||
|
@ -318,8 +341,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||||
{
|
{
|
||||||
"consensus state not found",
|
"consensus state not found",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: testClientID,
|
ChainID: testClientID,
|
||||||
ClientID: testClientID,
|
ClientID: testClientID,
|
||||||
},
|
},
|
||||||
|
@ -333,8 +356,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||||
{
|
{
|
||||||
"misbehaviour check failed",
|
"misbehaviour check failed",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothSigners),
|
Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||||
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), altValSet, altSigners),
|
Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
|
||||||
ChainID: testClientID,
|
ChainID: testClientID,
|
||||||
ClientID: testClientID,
|
ClientID: testClientID,
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keeper represents a type that grants read and write permissions to any client
|
// Keeper represents a type that grants read and write permissions to any client
|
||||||
|
@ -208,14 +206,11 @@ func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height uint64) (exported.
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
valSet := stakingtypes.Validators(histInfo.Valset)
|
|
||||||
|
|
||||||
consensusState := ibctmtypes.ConsensusState{
|
consensusState := ibctmtypes.ConsensusState{
|
||||||
Height: height,
|
Height: height,
|
||||||
Timestamp: histInfo.Header.Time,
|
Timestamp: histInfo.Header.Time,
|
||||||
Root: commitmenttypes.NewMerkleRoot(histInfo.Header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(histInfo.Header.AppHash),
|
||||||
NextValidatorsHash: histInfo.Header.NextValidatorsHash,
|
NextValidatorsHash: histInfo.Header.NextValidatorsHash,
|
||||||
ValidatorSet: tmtypes.NewValidatorSet(valSet.ToTmValidators()),
|
|
||||||
}
|
}
|
||||||
return consensusState, true
|
return consensusState, true
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
@ -45,6 +46,7 @@ type KeeperTestSuite struct {
|
||||||
consensusState ibctmtypes.ConsensusState
|
consensusState ibctmtypes.ConsensusState
|
||||||
header ibctmtypes.Header
|
header ibctmtypes.Header
|
||||||
valSet *tmtypes.ValidatorSet
|
valSet *tmtypes.ValidatorSet
|
||||||
|
valSetHash tmbytes.HexBytes
|
||||||
privVal tmtypes.PrivValidator
|
privVal tmtypes.PrivValidator
|
||||||
now time.Time
|
now time.Time
|
||||||
past time.Time
|
past time.Time
|
||||||
|
@ -68,13 +70,13 @@ func (suite *KeeperTestSuite) SetupTest() {
|
||||||
|
|
||||||
validator := tmtypes.NewValidator(pubKey, 1)
|
validator := tmtypes.NewValidator(pubKey, 1)
|
||||||
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||||
suite.header = ibctmtypes.CreateTestHeader(testChainID, testClientHeight, now2, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
suite.valSetHash = suite.valSet.Hash()
|
||||||
|
suite.header = ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight-1, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||||
suite.consensusState = ibctmtypes.ConsensusState{
|
suite.consensusState = ibctmtypes.ConsensusState{
|
||||||
Height: testClientHeight,
|
Height: testClientHeight,
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Root: commitmenttypes.NewMerkleRoot([]byte("hash")),
|
Root: commitmenttypes.NewMerkleRoot([]byte("hash")),
|
||||||
NextValidatorsHash: suite.valSet.Hash(),
|
NextValidatorsHash: suite.valSetHash,
|
||||||
ValidatorSet: suite.valSet,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var validators stakingtypes.Validators
|
var validators stakingtypes.Validators
|
||||||
|
@ -119,8 +121,6 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() {
|
||||||
suite.Require().True(found, "GetConsensusState failed")
|
suite.Require().True(found, "GetConsensusState failed")
|
||||||
|
|
||||||
tmConsState, ok := retrievedConsState.(ibctmtypes.ConsensusState)
|
tmConsState, ok := retrievedConsState.(ibctmtypes.ConsensusState)
|
||||||
// recalculate cached totalVotingPower field for equality check
|
|
||||||
tmConsState.ValidatorSet.TotalVotingPower()
|
|
||||||
suite.Require().True(ok)
|
suite.Require().True(ok)
|
||||||
suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly")
|
suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly")
|
||||||
}
|
}
|
||||||
|
@ -210,13 +210,14 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() {
|
||||||
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
|
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
|
||||||
|
|
||||||
nextState := ibctmtypes.ConsensusState{
|
nextState := ibctmtypes.ConsensusState{
|
||||||
Height: testClientHeight + 5,
|
Height: testClientHeight + 5,
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Root: commitmenttypes.NewMerkleRoot([]byte("next")),
|
Root: commitmenttypes.NewMerkleRoot([]byte("next")),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valSetHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
header := ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.header.Time.Add(time.Minute), suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
header := ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, testClientHeight, suite.header.Time.Add(time.Minute),
|
||||||
|
suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||||
|
|
||||||
// mock update functionality
|
// mock update functionality
|
||||||
clientState.LatestHeight = uint64(header.Height)
|
clientState.LatestHeight = uint64(header.Height)
|
||||||
|
@ -224,15 +225,11 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() {
|
||||||
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
|
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
|
||||||
|
|
||||||
latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID)
|
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().True(ok)
|
||||||
suite.Require().Equal(nextState, latest, "Latest client not returned correctly")
|
suite.Require().Equal(nextState, latest, "Latest client not returned correctly")
|
||||||
|
|
||||||
// Should return existing consensusState at latestClientHeight
|
// Should return existing consensusState at latestClientHeight
|
||||||
lte, ok := suite.keeper.GetClientConsensusStateLTE(suite.ctx, testClientID, testClientHeight+3)
|
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().True(ok)
|
||||||
suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", testClientHeight+3)
|
suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", testClientHeight+3)
|
||||||
}
|
}
|
||||||
|
@ -243,10 +240,10 @@ func (suite KeeperTestSuite) TestGetAllConsensusStates() {
|
||||||
testClientID,
|
testClientID,
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.consensusState.GetHeight(), nil, &tmtypes.ValidatorSet{},
|
suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.consensusState.GetHeight(), nil,
|
||||||
),
|
),
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
suite.consensusState.Timestamp.Add(time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash")), suite.consensusState.GetHeight()+1, nil, &tmtypes.ValidatorSet{},
|
suite.consensusState.Timestamp.Add(time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash")), suite.consensusState.GetHeight()+1, nil,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -254,7 +251,7 @@ func (suite KeeperTestSuite) TestGetAllConsensusStates() {
|
||||||
testClientID2,
|
testClientID2,
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
suite.consensusState.Timestamp.Add(2*time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash_2")), suite.consensusState.GetHeight()+2, nil, &tmtypes.ValidatorSet{},
|
suite.consensusState.Timestamp.Add(2*time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash_2")), suite.consensusState.GetHeight()+2, nil,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -36,7 +36,7 @@ func TestValidateGenesis(t *testing.T) {
|
||||||
val := tmtypes.NewValidator(pubKey, 10)
|
val := tmtypes.NewValidator(pubKey, 10)
|
||||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||||
|
|
||||||
header := ibctmtypes.CreateTestHeader(chainID, height, now, valSet, []tmtypes.PrivValidator{privVal})
|
header := ibctmtypes.CreateTestHeader(chainID, height, height-1, now, valSet, valSet, []tmtypes.PrivValidator{privVal})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -64,7 +64,7 @@ func TestValidateGenesis(t *testing.T) {
|
||||||
clientID,
|
clientID,
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), header.GetHeight(), header.ValidatorSet.Hash(), header.ValidatorSet,
|
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), header.GetHeight(), header.NextValidatorsHash,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -89,7 +89,7 @@ func TestValidateGenesis(t *testing.T) {
|
||||||
clientID,
|
clientID,
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), header.GetHeight(), header.ValidatorSet.Hash(), header.ValidatorSet,
|
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), header.GetHeight(), header.NextValidatorsHash,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -129,7 +129,7 @@ func TestValidateGenesis(t *testing.T) {
|
||||||
"CLIENTID2",
|
"CLIENTID2",
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), 0, header.ValidatorSet.Hash(), header.ValidatorSet,
|
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), 0, header.NextValidatorsHash,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -154,7 +154,7 @@ func TestValidateGenesis(t *testing.T) {
|
||||||
clientID,
|
clientID,
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), 0, header.ValidatorSet.Hash(), header.ValidatorSet,
|
header.Time, commitmenttypes.NewMerkleRoot(header.AppHash), 0, header.NextValidatorsHash,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package tendermint
|
package tendermint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
@ -66,7 +67,20 @@ func checkMisbehaviour(
|
||||||
infractionHeight := evidence.GetHeight()
|
infractionHeight := evidence.GetHeight()
|
||||||
infractionTime := evidence.GetTime()
|
infractionTime := evidence.GetTime()
|
||||||
ageDuration := currentTimestamp.Sub(infractionTime)
|
ageDuration := currentTimestamp.Sub(infractionTime)
|
||||||
ageBlocks := height - uint64(infractionHeight)
|
ageBlocks := uint64(infractionHeight) - height
|
||||||
|
|
||||||
|
// assert that trustedVals is NextValidators of last trusted header
|
||||||
|
// to do this, we check that trustedVals.Hash() == consState.NextValidatorsHash
|
||||||
|
trustedValsetHash1 := evidence.Header1.TrustedValidators.Hash()
|
||||||
|
trustedValsetHash2 := evidence.Header2.TrustedValidators.Hash()
|
||||||
|
|
||||||
|
if !bytes.Equal(consensusState.NextValidatorsHash, trustedValsetHash1) || !bytes.Equal(consensusState.NextValidatorsHash, trustedValsetHash2) {
|
||||||
|
return sdkerrors.Wrapf(
|
||||||
|
types.ErrInvalidValidatorSet,
|
||||||
|
"header's trusted validators %s, does not hash to either consensus state's trusted validator set. Expected: %X, got: TrustedValSet Header1 %X, TrustedValSet Header2 %X",
|
||||||
|
evidence.Header1.TrustedValidators, consensusState.NextValidatorsHash, trustedValsetHash1, trustedValsetHash2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Reject misbehaviour if the age is too old. Evidence is considered stale
|
// Reject misbehaviour if the age is too old. Evidence is considered stale
|
||||||
// if the difference in time and number of blocks is greater than the allowed
|
// if the difference in time and number of blocks is greater than the allowed
|
||||||
|
@ -108,18 +122,18 @@ func checkMisbehaviour(
|
||||||
|
|
||||||
// - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet
|
// - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet
|
||||||
// - ValidatorSets on both headers are valid given the last trusted ValidatorSet
|
// - ValidatorSets on both headers are valid given the last trusted ValidatorSet
|
||||||
if err := consensusState.ValidatorSet.VerifyCommitLightTrusting(
|
if err := evidence.Header1.TrustedValidators.VerifyCommitLightTrusting(
|
||||||
evidence.ChainID, evidence.Header1.Commit.BlockID, evidence.Header1.Height,
|
evidence.ChainID, evidence.Header1.Commit.BlockID, evidence.Header1.Height,
|
||||||
evidence.Header1.Commit, clientState.TrustLevel.ToTendermint(),
|
evidence.Header1.Commit, clientState.TrustLevel.ToTendermint(),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "validator set in header 1 has too much change from last known validator set: %v", err)
|
return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "validator set in header 1 has too much change from trusted validator set: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := consensusState.ValidatorSet.VerifyCommitLightTrusting(
|
if err := evidence.Header2.TrustedValidators.VerifyCommitLightTrusting(
|
||||||
evidence.ChainID, evidence.Header2.Commit.BlockID, evidence.Header2.Height,
|
evidence.ChainID, evidence.Header2.Commit.BlockID, evidence.Header2.Height,
|
||||||
evidence.Header2.Commit, clientState.TrustLevel.ToTendermint(),
|
evidence.Header2.Commit, clientState.TrustLevel.ToTendermint(),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "validator set in header 2 has too much change from last known validator set: %v", err)
|
return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "validator set in header 2 has too much change from trusted validator set: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -24,6 +24,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
|
|
||||||
// Create bothValSet with both suite validator and altVal
|
// Create bothValSet with both suite validator and altVal
|
||||||
bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal))
|
bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal))
|
||||||
|
bothValsHash := bothValSet.Hash()
|
||||||
// Create alternative validator set with only altVal
|
// Create alternative validator set with only altVal
|
||||||
altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal})
|
altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal})
|
||||||
|
|
||||||
|
@ -54,10 +55,10 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"valid misbehavior evidence",
|
"valid misbehavior evidence",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -69,10 +70,10 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"valid misbehavior at height greater than last consensusState",
|
"valid misbehavior at height greater than last consensusState",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -84,25 +85,25 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"consensus state's valset hash different from evidence should still pass",
|
"consensus state's valset hash different from evidence should still pass",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: suite.valSet},
|
types.ConsensusState{Timestamp: suite.now, Height: height, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: suite.valsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
simapp.DefaultConsensusParams,
|
simapp.DefaultConsensusParams,
|
||||||
height - 1,
|
height,
|
||||||
suite.now,
|
suite.now,
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"invalid tendermint client state",
|
"invalid tendermint client state",
|
||||||
nil,
|
nil,
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, altValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -114,10 +115,10 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"already frozen client state",
|
"already frozen client state",
|
||||||
types.ClientState{FrozenHeight: 1},
|
types.ClientState{FrozenHeight: 1},
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -131,8 +132,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
nil,
|
nil,
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -144,7 +145,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"invalid tendermint misbehaviour evidence",
|
"invalid tendermint misbehaviour evidence",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
nil,
|
nil,
|
||||||
simapp.DefaultConsensusParams,
|
simapp.DefaultConsensusParams,
|
||||||
height,
|
height,
|
||||||
|
@ -154,25 +155,27 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"rejected misbehaviour due to expired age",
|
"rejected misbehaviour due to expired age",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, int64(2*height+uint64(simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks)), height,
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
|
Header2: types.CreateTestHeader(chainID, int64(2*height+uint64(simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks)), height,
|
||||||
|
suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
simapp.DefaultConsensusParams,
|
simapp.DefaultConsensusParams,
|
||||||
2*height + uint64(simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks),
|
height,
|
||||||
suite.now.Add(2 * time.Minute).Add(simapp.DefaultConsensusParams.Evidence.MaxAgeDuration),
|
suite.now.Add(2 * time.Minute).Add(simapp.DefaultConsensusParams.Evidence.MaxAgeDuration),
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"provided height ≠ header height",
|
"provided height > header height",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -184,10 +187,25 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"unbonding period expired",
|
"unbonding period expired",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: time.Time{}, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: time.Time{}, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
|
ChainID: chainID,
|
||||||
|
ClientID: chainID,
|
||||||
|
},
|
||||||
|
simapp.DefaultConsensusParams,
|
||||||
|
height,
|
||||||
|
suite.now,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trusted validators is incorrect for given consensus state",
|
||||||
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
|
types.Evidence{
|
||||||
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||||
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -199,10 +217,10 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"first valset has too much change",
|
"first valset has too much change",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, altValSet, bothValSet, altSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), bothValSet, bothSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -214,10 +232,10 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"second valset has too much change",
|
"second valset has too much change",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), altValSet, altSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
@ -229,10 +247,10 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
||||||
{
|
{
|
||||||
"both valsets have too much change",
|
"both valsets have too much change",
|
||||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
types.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash},
|
||||||
types.Evidence{
|
types.Evidence{
|
||||||
Header1: types.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners),
|
Header1: types.CreateTestHeader(chainID, height, height, suite.now, altValSet, bothValSet, altSigners),
|
||||||
Header2: types.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), altValSet, altSigners),
|
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: chainID,
|
ClientID: chainID,
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
@ -29,6 +30,7 @@ type TendermintTestSuite struct {
|
||||||
signers []tmtypes.PrivValidator
|
signers []tmtypes.PrivValidator
|
||||||
privVal tmtypes.PrivValidator
|
privVal tmtypes.PrivValidator
|
||||||
valSet *tmtypes.ValidatorSet
|
valSet *tmtypes.ValidatorSet
|
||||||
|
valsHash tmbytes.HexBytes
|
||||||
header ibctmtypes.Header
|
header ibctmtypes.Header
|
||||||
now time.Time
|
now time.Time
|
||||||
clientTime time.Time
|
clientTime time.Time
|
||||||
|
@ -55,11 +57,12 @@ func (suite *TendermintTestSuite) SetupTest() {
|
||||||
|
|
||||||
val := tmtypes.NewValidator(pubKey, 10)
|
val := tmtypes.NewValidator(pubKey, 10)
|
||||||
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||||
|
suite.valsHash = suite.valSet.Hash()
|
||||||
|
|
||||||
// Suite header is intended to be header passed in for initial ClientState
|
// Suite header is intended to be header passed in for initial ClientState
|
||||||
// Thus it should have same height and time as ClientState
|
// Thus it should have same height and time as ClientState
|
||||||
// Note: default header has the same validator set suite.valSet as next validators set
|
// Note: default header has the same validator set suite.valSet as next validators set
|
||||||
suite.header = ibctmtypes.CreateTestHeader(chainID, height, suite.clientTime, suite.valSet, suite.signers)
|
suite.header = ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.clientTime, suite.valSet, suite.valSet, suite.signers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTendermintTestSuite(t *testing.T) {
|
func TestTendermintTestSuite(t *testing.T) {
|
||||||
|
|
|
@ -136,8 +136,8 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
|
||||||
name: "proof verification failed",
|
name: "proof verification failed",
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
@ -219,8 +219,8 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() {
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
connection: conn,
|
connection: conn,
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
@ -302,8 +302,8 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() {
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
channel: ch,
|
channel: ch,
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
@ -382,8 +382,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
commitment: []byte{},
|
commitment: []byte{},
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
@ -462,8 +462,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
ack: []byte{},
|
ack: []byte{},
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
@ -537,8 +537,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() {
|
||||||
name: "proof verification failed",
|
name: "proof verification failed",
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
@ -612,8 +612,8 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
|
||||||
name: "proof verification failed",
|
name: "proof verification failed",
|
||||||
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||||
consensusState: ibctmtypes.ConsensusState{
|
consensusState: ibctmtypes.ConsensusState{
|
||||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
|
||||||
proof: []byte{},
|
proof: []byte{},
|
||||||
|
|
|
@ -18,20 +18,18 @@ type ConsensusState struct {
|
||||||
Root commitmentexported.Root `json:"root" yaml:"root"`
|
Root commitmentexported.Root `json:"root" yaml:"root"`
|
||||||
Height uint64 `json:"height" yaml:"height"`
|
Height uint64 `json:"height" yaml:"height"`
|
||||||
NextValidatorsHash tmbytes.HexBytes `json:"next_validators_hash"` // validators hash for the next block
|
NextValidatorsHash tmbytes.HexBytes `json:"next_validators_hash"` // validators hash for the next block
|
||||||
ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConsensusState creates a new ConsensusState instance.
|
// NewConsensusState creates a new ConsensusState instance.
|
||||||
func NewConsensusState(
|
func NewConsensusState(
|
||||||
timestamp time.Time, root commitmentexported.Root, height uint64,
|
timestamp time.Time, root commitmentexported.Root, height uint64,
|
||||||
nextValsHash tmbytes.HexBytes, valset *tmtypes.ValidatorSet,
|
nextValsHash tmbytes.HexBytes,
|
||||||
) ConsensusState {
|
) ConsensusState {
|
||||||
return ConsensusState{
|
return ConsensusState{
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
Root: root,
|
Root: root,
|
||||||
Height: height,
|
Height: height,
|
||||||
NextValidatorsHash: nextValsHash,
|
NextValidatorsHash: nextValsHash,
|
||||||
ValidatorSet: valset,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +58,6 @@ func (cs ConsensusState) ValidateBasic() error {
|
||||||
if cs.Root == nil || cs.Root.Empty() {
|
if cs.Root == nil || cs.Root.Empty() {
|
||||||
return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "root cannot be empty")
|
return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "root cannot be empty")
|
||||||
}
|
}
|
||||||
if cs.ValidatorSet == nil {
|
|
||||||
return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "validator set cannot be nil")
|
|
||||||
}
|
|
||||||
if err := tmtypes.ValidateHash(cs.NextValidatorsHash); err != nil {
|
if err := tmtypes.ValidateHash(cs.NextValidatorsHash); err != nil {
|
||||||
return sdkerrors.Wrap(err, "next validators hash is invalid")
|
return sdkerrors.Wrap(err, "next validators hash is invalid")
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,50 +16,51 @@ func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() {
|
||||||
}{
|
}{
|
||||||
{"success",
|
{"success",
|
||||||
ibctmtypes.ConsensusState{
|
ibctmtypes.ConsensusState{
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Height: height,
|
Height: height,
|
||||||
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
true},
|
true},
|
||||||
{"root is nil",
|
{"root is nil",
|
||||||
ibctmtypes.ConsensusState{
|
ibctmtypes.ConsensusState{
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Height: height,
|
Height: height,
|
||||||
Root: nil,
|
Root: nil,
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
{"root is empty",
|
{"root is empty",
|
||||||
ibctmtypes.ConsensusState{
|
ibctmtypes.ConsensusState{
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Height: height,
|
Height: height,
|
||||||
Root: commitmenttypes.MerkleRoot{},
|
Root: commitmenttypes.MerkleRoot{},
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
{"valset is nil",
|
{"nextvalshash is invalid",
|
||||||
ibctmtypes.ConsensusState{
|
ibctmtypes.ConsensusState{
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Height: height,
|
Height: height,
|
||||||
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
||||||
ValidatorSet: nil,
|
NextValidatorsHash: []byte("hi"),
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
|
|
||||||
{"height is 0",
|
{"height is 0",
|
||||||
ibctmtypes.ConsensusState{
|
ibctmtypes.ConsensusState{
|
||||||
Timestamp: suite.now,
|
Timestamp: suite.now,
|
||||||
Height: 0,
|
Height: 0,
|
||||||
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
{"timestamp is zero",
|
{"timestamp is zero",
|
||||||
ibctmtypes.ConsensusState{
|
ibctmtypes.ConsensusState{
|
||||||
Timestamp: time.Time{},
|
Timestamp: time.Time{},
|
||||||
Height: height,
|
Height: height,
|
||||||
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")),
|
||||||
ValidatorSet: suite.valSet,
|
NextValidatorsHash: suite.valsHash,
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SubModuleName = "tendermint"
|
SubModuleName = "tendermint-client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IBC tendermint client sentinel errors
|
// IBC tendermint client sentinel errors
|
||||||
|
@ -19,4 +19,5 @@ var (
|
||||||
ErrTrustingPeriodExpired = sdkerrors.Register(SubModuleName, 8, "time since latest trusted state has passed the trusting period")
|
ErrTrustingPeriodExpired = sdkerrors.Register(SubModuleName, 8, "time since latest trusted state has passed the trusting period")
|
||||||
ErrUnbondingPeriodExpired = sdkerrors.Register(SubModuleName, 9, "time since latest trusted state has passed the unbonding period")
|
ErrUnbondingPeriodExpired = sdkerrors.Register(SubModuleName, 9, "time since latest trusted state has passed the unbonding period")
|
||||||
ErrInvalidProofSpecs = sdkerrors.Register(SubModuleName, 10, "invalid proof specs")
|
ErrInvalidProofSpecs = sdkerrors.Register(SubModuleName, 10, "invalid proof specs")
|
||||||
|
ErrInvalidValidatorSet = sdkerrors.Register(SubModuleName, 11, "invalid validator set")
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -85,6 +86,17 @@ func (ev Evidence) GetTime() time.Time {
|
||||||
|
|
||||||
// ValidateBasic implements Evidence interface
|
// ValidateBasic implements Evidence interface
|
||||||
func (ev Evidence) ValidateBasic() error {
|
func (ev Evidence) ValidateBasic() error {
|
||||||
|
if ev.Header1.TrustedHeight != ev.Header2.TrustedHeight {
|
||||||
|
return sdkerrors.Wrapf(ErrInvalidHeaderHeight, "evidence headers must share the same trusted height. got height1: %d, height2: %d",
|
||||||
|
ev.Header1.TrustedHeight, ev.Header2.TrustedHeight)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(ev.Header1.TrustedValidators.Hash(), ev.Header2.TrustedValidators.Hash()) {
|
||||||
|
return sdkerrors.Wrapf(ErrInvalidValidatorSet, "trusted validators on both submitted headers must be the same. Got valset1: %s, valset2: %s",
|
||||||
|
ev.Header1.TrustedValidators, ev.Header2.TrustedValidators)
|
||||||
|
}
|
||||||
|
if ev.Header1.TrustedValidators == nil {
|
||||||
|
return sdkerrors.Wrap(ErrInvalidValidatorSet, "trusted validator set cannot be empty")
|
||||||
|
}
|
||||||
if err := host.ClientIdentifierValidator(ev.ClientID); err != nil {
|
if err := host.ClientIdentifierValidator(ev.ClientID); err != nil {
|
||||||
return sdkerrors.Wrap(err, "evidence client ID is invalid")
|
return sdkerrors.Wrap(err, "evidence client ID is invalid")
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func (suite *TendermintTestSuite) TestEvidence() {
|
||||||
|
|
||||||
ev := ibctmtypes.Evidence{
|
ev := ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, signers),
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
}
|
}
|
||||||
|
@ -67,18 +67,40 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
"valid evidence",
|
"valid evidence",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now.Add(time.Minute), suite.valSet, signers),
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
},
|
},
|
||||||
func(ev *ibctmtypes.Evidence) error { return nil },
|
func(ev *ibctmtypes.Evidence) error { return nil },
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"trusted heights don't match",
|
||||||
|
ibctmtypes.Evidence{
|
||||||
|
Header1: suite.header,
|
||||||
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-2, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||||
|
ChainID: chainID,
|
||||||
|
ClientID: "gaiamainnet",
|
||||||
|
},
|
||||||
|
func(ev *ibctmtypes.Evidence) error { return nil },
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trusted valsets don't match",
|
||||||
|
ibctmtypes.Evidence{
|
||||||
|
Header1: suite.header,
|
||||||
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, bothValSet, signers),
|
||||||
|
ChainID: chainID,
|
||||||
|
ClientID: "gaiamainnet",
|
||||||
|
},
|
||||||
|
func(ev *ibctmtypes.Evidence) error { return nil },
|
||||||
|
false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"invalid client ID ",
|
"invalid client ID ",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, signers),
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "GAIA",
|
ClientID: "GAIA",
|
||||||
},
|
},
|
||||||
|
@ -89,7 +111,7 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
"wrong chainID on header1",
|
"wrong chainID on header1",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader("ethermint", height, suite.now, suite.valSet, signers),
|
Header2: ibctmtypes.CreateTestHeader("ethermint", height, height-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||||
ChainID: "ethermint",
|
ChainID: "ethermint",
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
},
|
},
|
||||||
|
@ -100,7 +122,7 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
"wrong chainID on header2",
|
"wrong chainID on header2",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader("ethermint", height, suite.now, suite.valSet, signers),
|
Header2: ibctmtypes.CreateTestHeader("ethermint", height, height-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
},
|
},
|
||||||
|
@ -111,7 +133,7 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
"mismatched heights",
|
"mismatched heights",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader(chainID, 6, suite.now, suite.valSet, signers),
|
Header2: ibctmtypes.CreateTestHeader(chainID, 6, 4, suite.now, suite.valSet, suite.valSet, signers),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
},
|
},
|
||||||
|
@ -132,7 +154,7 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
{
|
{
|
||||||
"header 1 doesn't have 2/3 majority",
|
"header 1 doesn't have 2/3 majority",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header1: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||||
Header2: suite.header,
|
Header2: suite.header,
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
|
@ -150,7 +172,7 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
"header 2 doesn't have 2/3 majority",
|
"header 2 doesn't have 2/3 majority",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
},
|
},
|
||||||
|
@ -167,7 +189,7 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() {
|
||||||
"validators sign off on wrong commit",
|
"validators sign off on wrong commit",
|
||||||
ibctmtypes.Evidence{
|
ibctmtypes.Evidence{
|
||||||
Header1: suite.header,
|
Header1: suite.header,
|
||||||
Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
Header2: ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
ClientID: "gaiamainnet",
|
ClientID: "gaiamainnet",
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,10 +14,20 @@ import (
|
||||||
|
|
||||||
var _ clientexported.Header = Header{}
|
var _ clientexported.Header = Header{}
|
||||||
|
|
||||||
// Header defines the Tendermint consensus Header
|
// Header defines the Tendermint client consensus Header.
|
||||||
|
// It encapsulates all the information necessary to update from a trusted Tendermint ConsensusState.
|
||||||
|
// The inclusion of TrustedHeight and TrustedValidators allows this update to process correctly, so long
|
||||||
|
// as the ConsensusState for the TrustedHeight exists, this removes race conditions among relayers
|
||||||
|
// The SignedHeader and ValidatorSet are the new untrusted update fields for the client.
|
||||||
|
// The TrustedHeight is the height of a stored ConsensusState on the client that will be used to verify the new untrusted header.
|
||||||
|
// The Trusted ConsensusState must be within the unbonding period of current time in order to correctly verify,
|
||||||
|
// and the TrustedValidators must hash to TrustedConsensusState.NextValidatorsHash since that is the last trusted validator set
|
||||||
|
// at the TrustedHeight.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
tmtypes.SignedHeader `json:"signed_header" yaml:"signed_header"` // contains the commitment root
|
tmtypes.SignedHeader `json:"signed_header" yaml:"signed_header"` // contains the commitment root
|
||||||
ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"`
|
ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` // the validator set that signed Header
|
||||||
|
TrustedHeight uint64 `json:"trusted_height" yaml:"trusted_height"` // the height of a trusted header seen by client less than or equal to Header
|
||||||
|
TrustedValidators *tmtypes.ValidatorSet `json:"trusted_vals" yaml:"trusted_vals"` // the last trusted validator set at trusted height
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientType defines that the Header is a Tendermint consensus algorithm
|
// ClientType defines that the Header is a Tendermint consensus algorithm
|
||||||
|
@ -25,13 +35,13 @@ func (h Header) ClientType() clientexported.ClientType {
|
||||||
return clientexported.Tendermint
|
return clientexported.Tendermint
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConsensusState returns the consensus state associated with the header
|
// ConsensusState returns the updated consensus state associated with the header
|
||||||
func (h Header) ConsensusState() ConsensusState {
|
func (h Header) ConsensusState() ConsensusState {
|
||||||
return ConsensusState{
|
return ConsensusState{
|
||||||
Height: uint64(h.Height),
|
Height: uint64(h.Height),
|
||||||
Timestamp: h.Time,
|
Timestamp: h.Time,
|
||||||
Root: commitmenttypes.NewMerkleRoot(h.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(h.AppHash),
|
||||||
ValidatorSet: h.ValidatorSet,
|
NextValidatorsHash: h.NextValidatorsHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +54,18 @@ func (h Header) GetHeight() uint64 {
|
||||||
|
|
||||||
// ValidateBasic calls the SignedHeader ValidateBasic function
|
// ValidateBasic calls the SignedHeader ValidateBasic function
|
||||||
// and checks that validatorsets are not nil
|
// and checks that validatorsets are not nil
|
||||||
|
// NOTE: TrustedHeight and TrustedValidators may be empty when creating client
|
||||||
|
// with MsgCreateClient
|
||||||
func (h Header) ValidateBasic(chainID string) error {
|
func (h Header) ValidateBasic(chainID string) error {
|
||||||
if err := h.SignedHeader.ValidateBasic(chainID); err != nil {
|
if err := h.SignedHeader.ValidateBasic(chainID); err != nil {
|
||||||
return sdkerrors.Wrap(err, "header failed basic validation")
|
return sdkerrors.Wrap(err, "header failed basic validation")
|
||||||
}
|
}
|
||||||
|
// TrustedHeight is less than Header for updates
|
||||||
|
// and less than or equal to Header for misbehaviour
|
||||||
|
if h.TrustedHeight > uint64(h.Height) {
|
||||||
|
return sdkerrors.Wrapf(ErrInvalidHeaderHeight, "TrustedHeight %d must be less than or equal to header height %d",
|
||||||
|
h.TrustedHeight, h.Height)
|
||||||
|
}
|
||||||
if h.ValidatorSet == nil {
|
if h.ValidatorSet == nil {
|
||||||
return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set is nil")
|
return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set is nil")
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() {
|
||||||
}{
|
}{
|
||||||
{"valid header", suite.header, chainID, true},
|
{"valid header", suite.header, chainID, true},
|
||||||
{"signed header basic validation failed", suite.header, "chainID", false},
|
{"signed header basic validation failed", suite.header, "chainID", false},
|
||||||
{"validator set nil", ibctmtypes.Header{suite.header.SignedHeader, nil}, chainID, false},
|
{"validator set nil", ibctmtypes.Header{suite.header.SignedHeader, nil, 0, suite.valSet}, chainID, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
suite.Require().Equal(clientexported.Tendermint, suite.header.ClientType())
|
suite.Require().Equal(clientexported.Tendermint, suite.header.ClientType())
|
||||||
|
|
|
@ -145,7 +145,6 @@ func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState {
|
||||||
Root: root,
|
Root: root,
|
||||||
Height: uint64(msg.Header.Height),
|
Height: uint64(msg.Header.Height),
|
||||||
NextValidatorsHash: msg.Header.NextValidatorsHash,
|
NextValidatorsHash: msg.Header.NextValidatorsHash,
|
||||||
ValidatorSet: msg.Header.ValidatorSet,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() {
|
func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() {
|
||||||
privKey := secp256k1.GenPrivKey()
|
privKey := secp256k1.GenPrivKey()
|
||||||
signer := sdk.AccAddress(privKey.PubKey().Address())
|
signer := sdk.AccAddress(privKey.PubKey().Address())
|
||||||
invalidHeader := types.CreateTestHeader(suite.header.ChainID, height, suite.now, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
invalidHeader := types.CreateTestHeader(suite.header.ChainID, height, 0, suite.now, suite.valSet, nil, []tmtypes.PrivValidator{suite.privVal})
|
||||||
invalidHeader.ValidatorSet = nil
|
invalidHeader.ValidatorSet = nil
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
@ -31,6 +32,7 @@ type TendermintTestSuite struct {
|
||||||
cdc codec.Marshaler
|
cdc codec.Marshaler
|
||||||
privVal tmtypes.PrivValidator
|
privVal tmtypes.PrivValidator
|
||||||
valSet *tmtypes.ValidatorSet
|
valSet *tmtypes.ValidatorSet
|
||||||
|
valsHash tmbytes.HexBytes
|
||||||
header ibctmtypes.Header
|
header ibctmtypes.Header
|
||||||
now time.Time
|
now time.Time
|
||||||
}
|
}
|
||||||
|
@ -50,7 +52,8 @@ func (suite *TendermintTestSuite) SetupTest() {
|
||||||
|
|
||||||
val := tmtypes.NewValidator(pubKey, 10)
|
val := tmtypes.NewValidator(pubKey, 10)
|
||||||
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||||
suite.header = ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
suite.valsHash = suite.valSet.Hash()
|
||||||
|
suite.header = ibctmtypes.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||||
suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, Time: suite.now})
|
suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, Time: suite.now})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ func MakeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTestHeader creates a mock header for testing only.
|
// CreateTestHeader creates a mock header for testing only.
|
||||||
func CreateTestHeader(chainID string, height int64, timestamp time.Time, valSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) Header {
|
func CreateTestHeader(chainID string, height, trustedHeight int64, timestamp time.Time, valSet, trustedVals *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) Header {
|
||||||
vsetHash := valSet.Hash()
|
vsetHash := valSet.Hash()
|
||||||
tmHeader := tmtypes.Header{
|
tmHeader := tmtypes.Header{
|
||||||
Version: version.Consensus{Block: 2, App: 2},
|
Version: version.Consensus{Block: 2, App: 2},
|
||||||
|
@ -54,7 +54,9 @@ func CreateTestHeader(chainID string, height int64, timestamp time.Time, valSet
|
||||||
}
|
}
|
||||||
|
|
||||||
return Header{
|
return Header{
|
||||||
SignedHeader: signedHeader,
|
SignedHeader: signedHeader,
|
||||||
ValidatorSet: valSet,
|
ValidatorSet: valSet,
|
||||||
|
TrustedHeight: uint64(trustedHeight),
|
||||||
|
TrustedValidators: trustedVals,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package tendermint
|
package tendermint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
lite "github.com/tendermint/tendermint/lite2"
|
lite "github.com/tendermint/tendermint/lite2"
|
||||||
|
@ -66,9 +67,21 @@ func CheckValidityAndUpdateState(
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkValidity checks if the Tendermint header is valid.
|
// checkValidity checks if the Tendermint header is valid.
|
||||||
|
// CONTRACT: consState.Height == header.TrustedHeight
|
||||||
func checkValidity(
|
func checkValidity(
|
||||||
clientState *types.ClientState, consState types.ConsensusState, header types.Header, currentTimestamp time.Time,
|
clientState *types.ClientState, consState types.ConsensusState,
|
||||||
|
header types.Header, currentTimestamp time.Time,
|
||||||
) error {
|
) error {
|
||||||
|
// assert that trustedVals is NextValidators of last trusted header
|
||||||
|
// to do this, we check that trustedVals.Hash() == consState.NextValidatorsHash
|
||||||
|
tvalHash := header.TrustedValidators.Hash()
|
||||||
|
if !bytes.Equal(consState.NextValidatorsHash, tvalHash) {
|
||||||
|
return sdkerrors.Wrapf(
|
||||||
|
types.ErrInvalidValidatorSet,
|
||||||
|
"trusted validators %s, does not hash to latest trusted validators. Expected: %X, got: %X",
|
||||||
|
header.TrustedValidators, consState.NextValidatorsHash, tvalHash,
|
||||||
|
)
|
||||||
|
}
|
||||||
// assert trusting period has not yet passed
|
// assert trusting period has not yet passed
|
||||||
if currentTimestamp.Sub(consState.Timestamp) >= clientState.TrustingPeriod {
|
if currentTimestamp.Sub(consState.Timestamp) >= clientState.TrustingPeriod {
|
||||||
return sdkerrors.Wrapf(
|
return sdkerrors.Wrapf(
|
||||||
|
@ -114,10 +127,10 @@ func checkValidity(
|
||||||
Header: &trustedHeader,
|
Header: &trustedHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify next header with the last header's validatorset as trusted validatorset
|
// Verify next header with the passed-in trustedVals
|
||||||
err := lite.Verify(
|
err := lite.Verify(
|
||||||
clientState.GetChainID(), &signedHeader,
|
clientState.GetChainID(), &signedHeader,
|
||||||
consState.ValidatorSet, &header.SignedHeader, header.ValidatorSet,
|
header.TrustedValidators, &header.SignedHeader, header.ValidatorSet,
|
||||||
clientState.TrustingPeriod, currentTimestamp, clientState.MaxClockDrift, clientState.TrustLevel.ToTendermint(),
|
clientState.TrustingPeriod, currentTimestamp, clientState.MaxClockDrift, clientState.TrustLevel.ToTendermint(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -136,7 +149,6 @@ func update(clientState *types.ClientState, header types.Header) (*types.ClientS
|
||||||
Timestamp: header.Time,
|
Timestamp: header.Time,
|
||||||
Root: commitmenttypes.NewMerkleRoot(header.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(header.AppHash),
|
||||||
NextValidatorsHash: header.NextValidatorsHash,
|
NextValidatorsHash: header.NextValidatorsHash,
|
||||||
ValidatorSet: header.ValidatorSet,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return clientState, consensusState
|
return clientState, consensusState
|
||||||
|
|
|
@ -55,8 +55,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "successful update with next height and same validator set",
|
name: "successful update with next height and same validator set",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: true,
|
expPass: true,
|
||||||
|
@ -65,8 +65,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "successful update with future height and different validator set",
|
name: "successful update with future height and different validator set",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+5, suite.headerTime, bothValSet, bothSigners)
|
newHeader = types.CreateTestHeader(chainID, height+5, height, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: true,
|
expPass: true,
|
||||||
|
@ -75,8 +75,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "successful update with next height and different validator set",
|
name: "successful update with next height and different validator set",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, bothValSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, bothValSet.Hash())
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.headerTime, bothValSet, bothSigners)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.headerTime, bothValSet, bothValSet, bothSigners)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: true,
|
expPass: true,
|
||||||
|
@ -85,8 +85,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "successful update for a previous height",
|
name: "successful update for a previous height",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height-3, bothValSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height-3, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height-1, suite.headerTime, bothValSet, bothSigners)
|
newHeader = types.CreateTestHeader(chainID, height-1, height-3, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: true,
|
expPass: true,
|
||||||
|
@ -95,8 +95,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "unsuccessful update with next height: update header mismatches nextValSetHash",
|
name: "unsuccessful update with next height: update header mismatches nextValSetHash",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.headerTime, bothValSet, bothSigners)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
|
@ -105,8 +105,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "unsuccessful update with next height: update header mismatches different nextValSetHash",
|
name: "unsuccessful update with next height: update header mismatches different nextValSetHash",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, bothValSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, bothValSet.Hash())
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.headerTime, suite.valSet, bothValSet, signers)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
|
@ -115,8 +115,18 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "unsuccessful update with future height: too much change in validator set",
|
name: "unsuccessful update with future height: too much change in validator set",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+5, suite.headerTime, altValSet, altSigners)
|
newHeader = types.CreateTestHeader(chainID, height+5, height, suite.headerTime, altValSet, suite.valSet, altSigners)
|
||||||
|
currentTime = suite.now
|
||||||
|
},
|
||||||
|
expPass: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unsuccessful updates, passed in incorrect trusted validators for given consensus state",
|
||||||
|
setup: func() {
|
||||||
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
|
newHeader = types.CreateTestHeader(chainID, height+5, height, suite.headerTime, bothValSet, bothValSet, bothSigners)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
|
@ -125,8 +135,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "unsuccessful update: trusting period has passed since last client timestamp",
|
name: "unsuccessful update: trusting period has passed since last client timestamp",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||||
// make current time pass trusting period from last timestamp on clientstate
|
// make current time pass trusting period from last timestamp on clientstate
|
||||||
currentTime = suite.now.Add(trustingPeriod)
|
currentTime = suite.now.Add(trustingPeriod)
|
||||||
},
|
},
|
||||||
|
@ -136,8 +146,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "unsuccessful update: header timestamp is past current timestamp",
|
name: "unsuccessful update: header timestamp is past current timestamp",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.now.Add(time.Minute), suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
|
@ -146,8 +156,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "unsuccessful update: header timestamp is not past last client timestamp",
|
name: "unsuccessful update: header timestamp is not past last client timestamp",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.clientTime, suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.clientTime, suite.valSet, suite.valSet, signers)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
|
@ -156,8 +166,8 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "header basic validation failed",
|
name: "header basic validation failed",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
newHeader = types.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height+1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||||
// cause new header to fail validatebasic by changing commit height to mismatch header height
|
// cause new header to fail validatebasic by changing commit height to mismatch header height
|
||||||
newHeader.SignedHeader.Commit.Height = height - 1
|
newHeader.SignedHeader.Commit.Height = height - 1
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
|
@ -168,9 +178,9 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
name: "header height < consensus height",
|
name: "header height < consensus height",
|
||||||
setup: func() {
|
setup: func() {
|
||||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height+5, commitmenttypes.GetSDKSpecs())
|
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height+5, commitmenttypes.GetSDKSpecs())
|
||||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valSet.Hash(), suite.valSet)
|
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.AppHash), height, suite.valsHash)
|
||||||
// Make new header at height less than latest client state
|
// Make new header at height less than latest client state
|
||||||
newHeader = types.CreateTestHeader(chainID, height-1, suite.headerTime, suite.valSet, signers)
|
newHeader = types.CreateTestHeader(chainID, height-1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||||
currentTime = suite.now
|
currentTime = suite.now
|
||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
|
@ -187,7 +197,6 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
||||||
Timestamp: newHeader.Time,
|
Timestamp: newHeader.Time,
|
||||||
Root: commitmenttypes.NewMerkleRoot(newHeader.AppHash),
|
Root: commitmenttypes.NewMerkleRoot(newHeader.AppHash),
|
||||||
NextValidatorsHash: newHeader.NextValidatorsHash,
|
NextValidatorsHash: newHeader.NextValidatorsHash,
|
||||||
ValidatorSet: newHeader.ValidatorSet,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newClientState, consensusState, err := tendermint.CheckValidityAndUpdateState(clientState, consensusState, newHeader, currentTime)
|
newClientState, consensusState, err := tendermint.CheckValidityAndUpdateState(clientState, consensusState, newHeader, currentTime)
|
||||||
|
|
|
@ -41,7 +41,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
|
||||||
clientID,
|
clientID,
|
||||||
[]exported.ConsensusState{
|
[]exported.ConsensusState{
|
||||||
ibctmtypes.NewConsensusState(
|
ibctmtypes.NewConsensusState(
|
||||||
suite.header.Time, commitmenttypes.NewMerkleRoot(suite.header.AppHash), suite.header.GetHeight(), suite.header.ValidatorSet.Hash(), suite.header.ValidatorSet,
|
suite.header.Time, commitmenttypes.NewMerkleRoot(suite.header.AppHash), suite.header.GetHeight(), suite.header.NextValidatorsHash,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -62,7 +62,7 @@ func (suite *IBCTestSuite) SetupTest() {
|
||||||
val := tmtypes.NewValidator(pubKey, 10)
|
val := tmtypes.NewValidator(pubKey, 10)
|
||||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||||
|
|
||||||
suite.header = ibctmtypes.CreateTestHeader(chainID, height, now, valSet, []tmtypes.PrivValidator{privVal})
|
suite.header = ibctmtypes.CreateTestHeader(chainID, height, height-1, now, valSet, valSet, []tmtypes.PrivValidator{privVal})
|
||||||
|
|
||||||
suite.cdc = suite.app.Codec()
|
suite.cdc = suite.app.Codec()
|
||||||
suite.ctx = suite.app.BaseApp.NewContext(isCheckTx, abci.Header{})
|
suite.ctx = suite.app.BaseApp.NewContext(isCheckTx, abci.Header{})
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/simapp"
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||||
|
@ -32,6 +33,7 @@ import (
|
||||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc/keeper"
|
"github.com/cosmos/cosmos-sdk/x/ibc/keeper"
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc/types"
|
"github.com/cosmos/cosmos-sdk/x/ibc/types"
|
||||||
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default params constants used to create a TM client
|
// Default params constants used to create a TM client
|
||||||
|
@ -244,6 +246,24 @@ func (chain *TestChain) GetClientState(clientID string) clientexported.ClientSta
|
||||||
return clientState
|
return clientState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConsensusState retrieves the consensus state for the provided clientID and height.
|
||||||
|
// It will return a success boolean depending on if consensus state exists or not.
|
||||||
|
func (chain *TestChain) GetConsensusState(clientID string, height uint64) (clientexported.ConsensusState, bool) {
|
||||||
|
return chain.App.IBCKeeper.ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValsAtHeight will return the validator set of the chain at a given height. It will return
|
||||||
|
// a success boolean depending on if the validator set exists or not at that height.
|
||||||
|
func (chain *TestChain) GetValsAtHeight(height int64) (*tmtypes.ValidatorSet, bool) {
|
||||||
|
histInfo, ok := chain.App.StakingKeeper.GetHistoricalInfo(chain.GetContext(), height)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
valSet := stakingtypes.Validators(histInfo.Valset)
|
||||||
|
return tmtypes.NewValidatorSet(valSet.ToTmValidators()), true
|
||||||
|
}
|
||||||
|
|
||||||
// GetConnection retrieves an IBC Connection for the provided TestConnection. The
|
// GetConnection retrieves an IBC Connection for the provided TestConnection. The
|
||||||
// connection is expected to exist otherwise testing will fail.
|
// connection is expected to exist otherwise testing will fail.
|
||||||
func (chain *TestChain) GetConnection(testConnection *TestConnection) connectiontypes.ConnectionEnd {
|
func (chain *TestChain) GetConnection(testConnection *TestConnection) connectiontypes.ConnectionEnd {
|
||||||
|
@ -331,9 +351,36 @@ func (chain *TestChain) CreateTMClient(counterparty *TestChain, clientID string)
|
||||||
|
|
||||||
// UpdateTMClient will construct and execute a 07-tendermint MsgUpdateClient. The counterparty
|
// UpdateTMClient will construct and execute a 07-tendermint MsgUpdateClient. The counterparty
|
||||||
// client will be updated on the (target) chain.
|
// client will be updated on the (target) chain.
|
||||||
|
// UpdateTMClient mocks the relayer flow necessary for updating a Tendermint client
|
||||||
func (chain *TestChain) UpdateTMClient(counterparty *TestChain, clientID string) error {
|
func (chain *TestChain) UpdateTMClient(counterparty *TestChain, clientID string) error {
|
||||||
|
header := counterparty.LastHeader
|
||||||
|
// Relayer must query for LatestHeight on client to get TrustedHeight
|
||||||
|
trustedHeight := chain.GetClientState(clientID).GetLatestHeight()
|
||||||
|
var (
|
||||||
|
trustedVals *tmtypes.ValidatorSet
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
// Once we get TrustedHeight from client, we must query the validators from the counterparty chain
|
||||||
|
// If the LatestHeight == LastHeader.Height, then TrustedValidators are current validators
|
||||||
|
// If LatestHeight < LastHeader.Height, we can query the historical validator set from HistoricalInfo
|
||||||
|
if trustedHeight == uint64(counterparty.LastHeader.Height) {
|
||||||
|
trustedVals = counterparty.Vals
|
||||||
|
} else {
|
||||||
|
// NOTE: We need to get validators from counterparty at height: trustedHeight+1
|
||||||
|
// since the last trusted validators for a header at height h
|
||||||
|
// is the NextValidators at h+1 committed to in header h by
|
||||||
|
// NextValidatorsHash
|
||||||
|
trustedVals, ok = counterparty.GetValsAtHeight(int64(trustedHeight + 1))
|
||||||
|
if !ok {
|
||||||
|
return sdkerrors.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// inject trusted fields into last header
|
||||||
|
header.TrustedHeight = trustedHeight
|
||||||
|
header.TrustedValidators = trustedVals
|
||||||
|
|
||||||
msg := ibctmtypes.NewMsgUpdateClient(
|
msg := ibctmtypes.NewMsgUpdateClient(
|
||||||
clientID, counterparty.LastHeader,
|
clientID, header,
|
||||||
chain.SenderAccount.GetAddress(),
|
chain.SenderAccount.GetAddress(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -373,6 +420,8 @@ func (chain *TestChain) CreateTMClientHeader() ibctmtypes.Header {
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not set trusted field here, these fields can be inserted before relaying messages to a client.
|
||||||
|
// The relayer is responsible for querying client and injecting appropriate trusted fields.
|
||||||
return ibctmtypes.Header{
|
return ibctmtypes.Header{
|
||||||
SignedHeader: signedHeader,
|
SignedHeader: signedHeader,
|
||||||
ValidatorSet: chain.Vals,
|
ValidatorSet: chain.Vals,
|
||||||
|
|
Loading…
Reference in New Issue