diff --git a/Makefile b/Makefile index e2fe1cfd0..f1acf9bac 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//') COMMIT := $(shell git log -1 --format='%H') SDKCOMMIT := $(shell go list -m -u -f '{{.Version}}' github.com/cosmos/cosmos-sdk) -GAIA_VERSION := v4.0.0 +GAIA_VERSION := v4.1.0 AKASH_VERSION := jack/update-sdk WASMD_VERSION := v0.14.1 diff --git a/relayer/misbehaviour.go b/relayer/misbehaviour.go new file mode 100644 index 000000000..2f8cd6a11 --- /dev/null +++ b/relayer/misbehaviour.go @@ -0,0 +1,87 @@ +package relayer + +import ( + "encoding/hex" + "fmt" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" + tmclient "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types" +) + +var ( + // strings for parsing events + updateCliTag = "update_client" + headerTag = "header" + clientIDTag = "client_id" +) + +// checkAndSubmitMisbehaviour check headers from update_client tx events +// against the associated light client. If the headers do not match, the emitted +// header and a reconstructed header are used in misbehaviour submission to +// the IBC client on the source chain. +func checkAndSubmitMisbehaviour(src *Chain, events map[string][]string) error { + hdrs, ok := events[fmt.Sprintf("%s.%s", updateCliTag, headerTag)] + if !ok { + return nil + } + for i, hdr := range hdrs { + clientIDs := events[fmt.Sprintf("%s.%s", updateCliTag, clientIDTag)] + if len(clientIDs) <= i { + return fmt.Errorf("emitted client-ids count is less than emitted headers count") + } + + emittedClientID := clientIDs[i] + if src.PathEnd.ClientID != emittedClientID { + continue + } + + hdrBytes, err := hex.DecodeString(hdr) + if err != nil { + return sdkerrors.Wrapf(err, "failed decoding hexadecimal string of header with client-id: %s", + emittedClientID) + } + + exportedHeader, err := clienttypes.UnmarshalHeader(src.Encoding.Marshaler, hdrBytes) + if err != nil { + return sdkerrors.Wrapf(err, "failed unmarshaling header with client-id: %s", emittedClientID) + } + + emittedHeader, ok := exportedHeader.(*tmclient.Header) + if !ok { + return fmt.Errorf("emitted header is not tendermint type") + } + + trustedHeader, err := src.GetLightSignedHeaderAtHeight(emittedHeader.Header.Height) + if err != nil { + return err + } + + if IsMatchingConsensusState(emittedHeader.ConsensusState(), trustedHeader.ConsensusState()) { + continue + } + + trustedHeader.TrustedValidators = emittedHeader.TrustedValidators + trustedHeader.TrustedHeight = emittedHeader.TrustedHeight + + misbehaviour := tmclient.NewMisbehaviour(emittedClientID, emittedHeader, trustedHeader) + msg, err := clienttypes.NewMsgSubmitMisbehaviour(emittedClientID, misbehaviour, src.MustGetAddress()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + res, success, err := src.SendMsg(msg) + if err != nil { + return err + } + if !success { + return fmt.Errorf("submit misbehaviour tx failed: %s", res.RawLog) + } + src.Log(fmt.Sprintf("Submitted misbehaviour for emitted header with height: %d", + emittedHeader.Header.Height)) + } + + return nil +} diff --git a/relayer/naive-strategy.go b/relayer/naive-strategy.go index b33106154..9892ac0ba 100644 --- a/relayer/naive-strategy.go +++ b/relayer/naive-strategy.go @@ -232,6 +232,12 @@ func (nrs *NaiveStrategy) UnrelayedAcknowledgements(src, dst *Chain) (*RelaySequ // HandleEvents defines how the relayer will handle block and transaction events as they are emitted func (nrs *NaiveStrategy) HandleEvents(src, dst *Chain, events map[string][]string) { + // check for misbehaviour and submit if found + err := checkAndSubmitMisbehaviour(src, events) + if err != nil { + src.Error(err) + } + rlyPackets, err := relayPacketsFromEventListener(src.PathEnd, dst.PathEnd, events) if len(rlyPackets) > 0 && err == nil { nrs.sendTxFromEventPackets(src, dst, rlyPackets)