Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
696 lines
33 KiB
Go
696 lines
33 KiB
Go
package tendermint_test
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
cmttypes "git.cw.tr/mukan-network/mukan-consensus/types"
|
|
|
|
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
|
|
solomachine "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/06-solomachine"
|
|
ibctm "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/07-tendermint"
|
|
ibctesting "git.cw.tr/mukan-network/mukan-ibc/testing"
|
|
)
|
|
|
|
func (suite *TendermintTestSuite) TestVerifyMisbehaviour() {
|
|
// Setup different validators and signers for testing different types of updates
|
|
altPrivVal := cmttypes.NewMockPV()
|
|
altPubKey, err := altPrivVal.GetPubKey()
|
|
suite.Require().NoError(err)
|
|
|
|
// create modified heights to use for test-cases
|
|
altVal := cmttypes.NewValidator(altPubKey, 100)
|
|
|
|
// Create alternative validator set with only altVal, invalid update (too much change in valSet)
|
|
altValSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{altVal})
|
|
altSigners := getAltSigners(altVal, altPrivVal)
|
|
|
|
var (
|
|
path *ibctesting.Path
|
|
misbehaviour exported.ClientMessage
|
|
)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func()
|
|
expErr error
|
|
}{
|
|
{
|
|
"valid fork misbehaviour", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid time misbehaviour", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+3, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid time misbehaviour, header 1 time strictly less than header 2 time", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+3, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Hour), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid misbehavior at height greater than last consensusState", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+1, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+1, trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, nil,
|
|
},
|
|
{
|
|
"valid misbehaviour with different trusted heights", func() {
|
|
trustedHeight1, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals1, ok := suite.chainB.TrustedValidators[trustedHeight1.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
trustedHeight2, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals2, ok := suite.chainB.TrustedValidators[trustedHeight2.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight1, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals1, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight2, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals2, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid misbehaviour at a previous revision", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
|
|
// increment revision number
|
|
err = path.EndpointB.UpgradeChain()
|
|
suite.Require().NoError(err)
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid misbehaviour at a future revision", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
futureRevision := fmt.Sprintf("%s-%d", strings.TrimSuffix(suite.chainB.ChainID, fmt.Sprintf("-%d", clienttypes.ParseChainID(suite.chainB.ChainID))), height.GetRevisionNumber()+1)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(futureRevision, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(futureRevision, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid misbehaviour with trusted heights at a previous revision", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
// increment revision of chainID
|
|
err = path.EndpointB.UpgradeChain()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"consensus state's valset hash different from misbehaviour should still pass", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
// Create bothValSet with both suite validator and altVal
|
|
bothValSet := cmttypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altValSet.Proposer))
|
|
bothSigners := suite.chainB.Signers
|
|
bothSigners[altValSet.Proposer.Address.String()] = altPrivVal
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), bothValSet, suite.chainB.NextVals, trustedVals, bothSigners),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, bothValSet, suite.chainB.NextVals, trustedVals, bothSigners),
|
|
}
|
|
}, nil,
|
|
},
|
|
{
|
|
"invalid misbehaviour: misbehaviour from different chain", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("invalid light client misbehaviour"),
|
|
},
|
|
{
|
|
"misbehaviour trusted validators does not match validator hash in trusted consensus state", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
err := path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("invalid validator set"),
|
|
},
|
|
{
|
|
"trusted consensus state does not exist", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight.Increment().(clienttypes.Height), suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("consensus state not found"),
|
|
},
|
|
{
|
|
"invalid tendermint misbehaviour", func() {
|
|
misbehaviour = &solomachine.Misbehaviour{}
|
|
}, errors.New("invalid client type"),
|
|
},
|
|
{
|
|
"trusting period expired", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
suite.chainA.ExpireClient(path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("time since latest trusted state has passed the trusting period"),
|
|
},
|
|
{
|
|
"header 1 valset has too much change", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
{
|
|
"header 2 valset has too much change", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
{
|
|
"both header 1 and header 2 valsets have too much change", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.SetupTest()
|
|
path = ibctesting.NewPath(suite.chainA, suite.chainB)
|
|
|
|
err := path.EndpointA.CreateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
lightClientModule, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(suite.chainA.GetContext(), path.EndpointA.ClientID)
|
|
suite.Require().NoError(err)
|
|
|
|
tc.malleate()
|
|
|
|
err = lightClientModule.VerifyClientMessage(suite.chainA.GetContext(), path.EndpointA.ClientID, misbehaviour)
|
|
|
|
if tc.expErr == nil {
|
|
suite.Require().NoError(err)
|
|
} else {
|
|
suite.Require().Error(err)
|
|
suite.Require().ErrorContains(err, tc.expErr.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// test both fork and time misbehaviour for chainIDs not in the revision format
|
|
// this function is separate as it must use a global variable in the testing package
|
|
// to initialize chains not in the revision format
|
|
func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() {
|
|
// NOTE: chains set to non revision format
|
|
ibctesting.ChainIDSuffix = ""
|
|
|
|
// Setup different validators and signers for testing different types of updates
|
|
altPrivVal := cmttypes.NewMockPV()
|
|
altPubKey, err := altPrivVal.GetPubKey()
|
|
suite.Require().NoError(err)
|
|
|
|
// create modified heights to use for test-cases
|
|
altVal := cmttypes.NewValidator(altPubKey, 100)
|
|
|
|
// Create alternative validator set with only altVal, invalid update (too much change in valSet)
|
|
altValSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{altVal})
|
|
altSigners := getAltSigners(altVal, altPrivVal)
|
|
|
|
var (
|
|
path *ibctesting.Path
|
|
misbehaviour exported.ClientMessage
|
|
)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func()
|
|
expErr error
|
|
}{
|
|
{
|
|
"valid fork misbehaviour", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid time misbehaviour", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+3, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid time misbehaviour, header 1 time strictly less than header 2 time", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+3, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Hour), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"valid misbehavior at height greater than last consensusState", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+1, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height+1, trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, nil,
|
|
},
|
|
{
|
|
"valid misbehaviour with different trusted heights", func() {
|
|
trustedHeight1, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals1, ok := suite.chainB.TrustedValidators[trustedHeight1.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
trustedHeight2, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals2, ok := suite.chainB.TrustedValidators[trustedHeight2.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight1, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals1, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight2, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals2, suite.chainB.Signers),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"consensus state's valset hash different from misbehaviour should still pass", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
// Create bothValSet with both suite validator and altVal
|
|
bothValSet := cmttypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altValSet.Proposer))
|
|
bothSigners := suite.chainB.Signers
|
|
bothSigners[altValSet.Proposer.Address.String()] = altPrivVal
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), bothValSet, suite.chainB.NextVals, trustedVals, bothSigners),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, bothValSet, suite.chainB.NextVals, trustedVals, bothSigners),
|
|
}
|
|
}, nil,
|
|
},
|
|
{
|
|
"invalid misbehaviour: misbehaviour from different chain", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
{
|
|
"misbehaviour trusted validators does not match validator hash in trusted consensus state", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("invalid validator set"),
|
|
},
|
|
{
|
|
"trusted consensus state does not exist", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight.Increment().(clienttypes.Height), suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, suite.chainB.ProposedHeader.Height, trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("consensus state not found"),
|
|
},
|
|
{
|
|
"invalid tendermint misbehaviour", func() {
|
|
misbehaviour = &solomachine.Misbehaviour{}
|
|
}, errors.New("nvalid client type"),
|
|
},
|
|
{
|
|
"trusting period expired", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
suite.chainA.ExpireClient(path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("time since latest trusted state has passed the trusting period"),
|
|
},
|
|
{
|
|
"header 1 valset has too much change", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
{
|
|
"header 2 valset has too much change", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
{
|
|
"both header 1 and header 2 valsets have too much change", func() {
|
|
trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
trustedVals, ok := suite.chainB.TrustedValidators[trustedHeight.RevisionHeight]
|
|
suite.Require().True(ok)
|
|
|
|
err = path.EndpointA.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
height, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height)
|
|
suite.Require().True(ok)
|
|
|
|
misbehaviour = &ibctm.Misbehaviour{
|
|
Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
Header2: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time, altValSet, suite.chainB.NextVals, trustedVals, altSigners),
|
|
}
|
|
}, errors.New("validator set in header has too much change from trusted validator set"),
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.SetupTest()
|
|
path = ibctesting.NewPath(suite.chainA, suite.chainB)
|
|
|
|
err := path.EndpointA.CreateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
lightClientModule, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(suite.chainA.GetContext(), path.EndpointA.ClientID)
|
|
suite.Require().NoError(err)
|
|
|
|
tc.malleate()
|
|
|
|
err = lightClientModule.VerifyClientMessage(suite.chainA.GetContext(), path.EndpointA.ClientID, misbehaviour)
|
|
|
|
if tc.expErr == nil {
|
|
suite.Require().NoError(err)
|
|
} else {
|
|
suite.Require().Error(err)
|
|
suite.Require().ErrorContains(err, tc.expErr.Error())
|
|
}
|
|
})
|
|
}
|
|
|
|
// NOTE: reset chain creation to revision format
|
|
ibctesting.ChainIDSuffix = "-1"
|
|
}
|