mukan-ibc/modules/light-clients/07-tendermint/misbehaviour.go
Mukan Erkin Törük 6852832fe8
Some checks failed
CodeQL / Analyze (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (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
Deploy to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled
Buf-Push / push (push) Has been cancelled
initial: sovereign Mukan Network fork
2026-05-11 03:18:28 +03:00

125 lines
4.6 KiB
Go

package tendermint
import (
"time"
errorsmod "cosmossdk.io/errors"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
cmttypes "github.com/cometbft/cometbft/types"
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
host "github.com/cosmos/ibc-go/v10/modules/core/24-host"
"github.com/cosmos/ibc-go/v10/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
}