Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

chore: move Tendermint CheckForMisbehaviour to misbehaviour_handle.go #2803

Merged
merged 5 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions modules/light-clients/06-solomachine/misbehaviour_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,34 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

commitmenttypes "github.com/cosmos/ibc-go/v6/modules/core/23-commitment/types"
"github.com/cosmos/ibc-go/v6/modules/core/exported"
)

// CheckForMisbehaviour returns true for type Misbehaviour (passed VerifyClientMessage check), otherwise returns false
func (cs ClientState) CheckForMisbehaviour(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, clientMsg exported.ClientMessage) bool {
if _, ok := clientMsg.(*Misbehaviour); ok {
return true
}

return false
}

func (cs ClientState) verifyMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, misbehaviour *Misbehaviour) error {
// NOTE: a check that the misbehaviour message data are not equal is done by
// misbehaviour.ValidateBasic which is called by the 02-client keeper.
// verify first signature
if err := cs.verifySignatureAndData(cdc, misbehaviour, misbehaviour.SignatureOne); err != nil {
return sdkerrors.Wrap(err, "failed to verify signature one")
}

// verify second signature
if err := cs.verifySignatureAndData(cdc, misbehaviour, misbehaviour.SignatureTwo); err != nil {
return sdkerrors.Wrap(err, "failed to verify signature two")
}

return nil
}

// verifySignatureAndData verifies that the currently registered public key has signed
// over the provided data and that the data is valid. The data is valid if it can be
// unmarshaled into the specified data type.
Expand Down Expand Up @@ -47,19 +73,3 @@ func (cs ClientState) verifySignatureAndData(cdc codec.BinaryCodec, misbehaviour

return nil
}

func (cs ClientState) verifyMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, misbehaviour *Misbehaviour) error {
// NOTE: a check that the misbehaviour message data are not equal is done by
// misbehaviour.ValidateBasic which is called by the 02-client keeper.
// verify first signature
if err := cs.verifySignatureAndData(cdc, misbehaviour, misbehaviour.SignatureOne); err != nil {
return sdkerrors.Wrap(err, "failed to verify signature one")
}

// verify second signature
if err := cs.verifySignatureAndData(cdc, misbehaviour, misbehaviour.SignatureTwo); err != nil {
return sdkerrors.Wrap(err, "failed to verify signature two")
}

return nil
}
9 changes: 0 additions & 9 deletions modules/light-clients/06-solomachine/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,6 @@ func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, client
return []exported.Height{clienttypes.NewHeight(0, cs.Sequence)}
}

// CheckForMisbehaviour returns true for type Misbehaviour (passed VerifyClientMessage check), otherwise returns false
func (cs ClientState) CheckForMisbehaviour(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, clientMsg exported.ClientMessage) bool {
if _, ok := clientMsg.(*Misbehaviour); ok {
return true
}

return false
}

// UpdateStateOnMisbehaviour updates state upon misbehaviour. This method should only be called on misbehaviour
// as it does not perform any misbehaviour checks.
func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, _ exported.ClientMessage) {
Expand Down
47 changes: 47 additions & 0 deletions modules/light-clients/07-tendermint/misbehaviour_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tendermint

import (
"bytes"
"reflect"
"time"

"github.com/cosmos/cosmos-sdk/codec"
Expand All @@ -10,8 +11,54 @@ import (
tmtypes "github.com/tendermint/tendermint/types"

clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
"github.com/cosmos/ibc-go/v6/modules/core/exported"
)

// CheckForMisbehaviour detects duplicate height misbehaviour and BFT time violation misbehaviour
func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as on solomachine, I think verifyMisbehaviour can go first

switch msg := msg.(type) {
case *Header:
tmHeader := msg
consState := tmHeader.ConsensusState()

// Check if the Client store already has a consensus state for the header's height
// If the consensus state exists, and it matches the header then we return early
// since header has already been submitted in a previous UpdateClient.
existingConsState, _ := GetConsensusState(clientStore, cdc, tmHeader.GetHeight())
if existingConsState != nil {
// This header has already been submitted and the necessary state is already stored
// in client store, thus we can return early without further validation.
if reflect.DeepEqual(existingConsState, tmHeader.ConsensusState()) { //nolint:gosimple
return false
}

// A consensus state already exists for this height, but it does not match the provided header.
// The assumption is that Header has already been validated. Thus we can return true as misbehaviour is present
return true
}

// Check that consensus state timestamps are monotonic
prevCons, prevOk := GetPreviousConsensusState(clientStore, cdc, tmHeader.GetHeight())
nextCons, nextOk := GetNextConsensusState(clientStore, cdc, tmHeader.GetHeight())
// if previous consensus state exists, check consensus state time is greater than previous consensus state time
// if previous consensus state is not before current consensus state return true
if prevOk && !prevCons.Timestamp.Before(consState.Timestamp) {
return true
}
// if next consensus state exists, check consensus state time is less than next consensus state time
// if next consensus state is not after current consensus state return true
if nextOk && !nextCons.Timestamp.After(consState.Timestamp) {
return true
}
case *Misbehaviour:
// The correctness of Misbehaviour ClientMessage types is ensured by calling VerifyClientMessage prior to this function
// Thus, here we can return true, as ClientMessage is of type Misbehaviour
return true
}

return false
}

// verifyMisbehaviour determines whether or not two conflicting
// headers at the same height would have convinced the light client.
//
Expand Down
46 changes: 0 additions & 46 deletions modules/light-clients/07-tendermint/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package tendermint
import (
"bytes"
"fmt"
"reflect"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -195,51 +194,6 @@ func (cs ClientState) pruneOldestConsensusState(ctx sdk.Context, cdc codec.Binar
}
}

// CheckForMisbehaviour detects duplicate height misbehaviour and BFT time violation misbehaviour
func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) bool {
switch msg := msg.(type) {
case *Header:
tmHeader := msg
consState := tmHeader.ConsensusState()

// Check if the Client store already has a consensus state for the header's height
// If the consensus state exists, and it matches the header then we return early
// since header has already been submitted in a previous UpdateClient.
existingConsState, _ := GetConsensusState(clientStore, cdc, tmHeader.GetHeight())
if existingConsState != nil {
// This header has already been submitted and the necessary state is already stored
// in client store, thus we can return early without further validation.
if reflect.DeepEqual(existingConsState, tmHeader.ConsensusState()) { //nolint:gosimple
return false
}

// A consensus state already exists for this height, but it does not match the provided header.
// The assumption is that Header has already been validated. Thus we can return true as misbehaviour is present
return true
}

// Check that consensus state timestamps are monotonic
prevCons, prevOk := GetPreviousConsensusState(clientStore, cdc, tmHeader.GetHeight())
nextCons, nextOk := GetNextConsensusState(clientStore, cdc, tmHeader.GetHeight())
// if previous consensus state exists, check consensus state time is greater than previous consensus state time
// if previous consensus state is not before current consensus state return true
if prevOk && !prevCons.Timestamp.Before(consState.Timestamp) {
return true
}
// if next consensus state exists, check consensus state time is less than next consensus state time
// if next consensus state is not after current consensus state return true
if nextOk && !nextCons.Timestamp.After(consState.Timestamp) {
return true
}
case *Misbehaviour:
// The correctness of Misbehaviour ClientMessage types is ensured by calling VerifyClientMessage prior to this function
// Thus, here we can return true, as ClientMessage is of type Misbehaviour
return true
}

return false
}

// UpdateStateOnMisbehaviour updates state upon misbehaviour, freezing the ClientState. This method should only be called when misbehaviour is detected
// as it does not perform any misbehaviour checks.
func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, _ exported.ClientMessage) {
Expand Down