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
125 lines
4.6 KiB
Go
125 lines
4.6 KiB
Go
package tendermint
|
|
|
|
import (
|
|
"time"
|
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
cmtproto "git.cw.tr/mukan-network/mukan-consensus/proto/tendermint/types"
|
|
cmttypes "git.cw.tr/mukan-network/mukan-consensus/types"
|
|
|
|
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
|
|
host "git.cw.tr/mukan-network/mukan-ibc/modules/core/24-host"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
|
|
)
|
|
|
|
var _ exported.ClientMessage = (*Misbehaviour)(nil)
|
|
|
|
// FrozenHeight is same for all misbehaviour
|
|
var FrozenHeight = clienttypes.NewHeight(0, 1)
|
|
|
|
// NewMisbehaviour creates a new Misbehaviour instance.
|
|
func NewMisbehaviour(clientID string, header1, header2 *Header) *Misbehaviour {
|
|
return &Misbehaviour{
|
|
ClientId: clientID,
|
|
Header1: header1,
|
|
Header2: header2,
|
|
}
|
|
}
|
|
|
|
// ClientType is Tendermint light client
|
|
func (Misbehaviour) ClientType() string {
|
|
return exported.Tendermint
|
|
}
|
|
|
|
// GetTime returns the timestamp at which misbehaviour occurred. It uses the
|
|
// maximum value from both headers to prevent producing an invalid header outside
|
|
// of the misbehaviour age range.
|
|
func (misbehaviour Misbehaviour) GetTime() time.Time {
|
|
t1, t2 := misbehaviour.Header1.GetTime(), misbehaviour.Header2.GetTime()
|
|
if t1.After(t2) {
|
|
return t1
|
|
}
|
|
return t2
|
|
}
|
|
|
|
// ValidateBasic implements Misbehaviour interface
|
|
func (misbehaviour Misbehaviour) ValidateBasic() error {
|
|
if misbehaviour.Header1 == nil {
|
|
return errorsmod.Wrap(ErrInvalidHeader, "misbehaviour Header1 cannot be nil")
|
|
}
|
|
if misbehaviour.Header2 == nil {
|
|
return errorsmod.Wrap(ErrInvalidHeader, "misbehaviour Header2 cannot be nil")
|
|
}
|
|
if misbehaviour.Header1.TrustedHeight.RevisionHeight == 0 {
|
|
return errorsmod.Wrapf(ErrInvalidHeaderHeight, "misbehaviour Header1 cannot have zero revision height")
|
|
}
|
|
if misbehaviour.Header2.TrustedHeight.RevisionHeight == 0 {
|
|
return errorsmod.Wrapf(ErrInvalidHeaderHeight, "misbehaviour Header2 cannot have zero revision height")
|
|
}
|
|
if misbehaviour.Header1.TrustedValidators == nil {
|
|
return errorsmod.Wrap(ErrInvalidValidatorSet, "trusted validator set in Header1 cannot be empty")
|
|
}
|
|
if misbehaviour.Header2.TrustedValidators == nil {
|
|
return errorsmod.Wrap(ErrInvalidValidatorSet, "trusted validator set in Header2 cannot be empty")
|
|
}
|
|
if misbehaviour.Header1.Header.ChainID != misbehaviour.Header2.Header.ChainID {
|
|
return errorsmod.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers must have identical chainIDs")
|
|
}
|
|
|
|
if err := host.ClientIdentifierValidator(misbehaviour.ClientId); err != nil {
|
|
return errorsmod.Wrap(err, "misbehaviour client ID is invalid")
|
|
}
|
|
|
|
// ValidateBasic on both validators
|
|
if err := misbehaviour.Header1.ValidateBasic(); err != nil {
|
|
return errorsmod.Wrap(
|
|
clienttypes.ErrInvalidMisbehaviour,
|
|
errorsmod.Wrap(err, "header 1 failed validation").Error(),
|
|
)
|
|
}
|
|
if err := misbehaviour.Header2.ValidateBasic(); err != nil {
|
|
return errorsmod.Wrap(
|
|
clienttypes.ErrInvalidMisbehaviour,
|
|
errorsmod.Wrap(err, "header 2 failed validation").Error(),
|
|
)
|
|
}
|
|
// Ensure that Height1 is greater than or equal to Height2
|
|
if misbehaviour.Header1.GetHeight().LT(misbehaviour.Header2.GetHeight()) {
|
|
return errorsmod.Wrapf(clienttypes.ErrInvalidMisbehaviour, "Header1 height is less than Header2 height (%s < %s)", misbehaviour.Header1.GetHeight(), misbehaviour.Header2.GetHeight())
|
|
}
|
|
|
|
blockID1, err := cmttypes.BlockIDFromProto(&misbehaviour.Header1.Commit.BlockID)
|
|
if err != nil {
|
|
return errorsmod.Wrap(err, "invalid block ID from header 1 in misbehaviour")
|
|
}
|
|
blockID2, err := cmttypes.BlockIDFromProto(&misbehaviour.Header2.Commit.BlockID)
|
|
if err != nil {
|
|
return errorsmod.Wrap(err, "invalid block ID from header 2 in misbehaviour")
|
|
}
|
|
|
|
if err := validCommit(misbehaviour.Header1.Header.ChainID, *blockID1,
|
|
misbehaviour.Header1.Commit, misbehaviour.Header1.ValidatorSet); err != nil {
|
|
return err
|
|
}
|
|
return validCommit(misbehaviour.Header2.Header.ChainID, *blockID2,
|
|
misbehaviour.Header2.Commit, misbehaviour.Header2.ValidatorSet)
|
|
}
|
|
|
|
// validCommit checks if the given commit is a valid commit from the passed-in validatorset
|
|
func validCommit(chainID string, blockID cmttypes.BlockID, commit *cmtproto.Commit, valSet *cmtproto.ValidatorSet) (err error) {
|
|
tmCommit, err := cmttypes.CommitFromProto(commit)
|
|
if err != nil {
|
|
return errorsmod.Wrap(err, "commit is not tendermint commit type")
|
|
}
|
|
tmValset, err := cmttypes.ValidatorSetFromProto(valSet)
|
|
if err != nil {
|
|
return errorsmod.Wrap(err, "validator set is not tendermint validator set type")
|
|
}
|
|
|
|
if err := tmValset.VerifyCommitLight(chainID, blockID, tmCommit.Height, tmCommit); err != nil {
|
|
return errorsmod.Wrap(clienttypes.ErrInvalidMisbehaviour, "validator set did not commit to header")
|
|
}
|
|
|
|
return nil
|
|
}
|