Skip to content

Commit

Permalink
Emit header in MsgUpdateClient events (#8624)
Browse files Browse the repository at this point in the history
* emit header in update client msg

* update CHANGELOG

* update spec

* fix nil header bug

* use JSON encoding for emitting header

* Update x/ibc/core/spec/06_events.md

* use proto for encoding

* add tests

* encode to hex before emitting header in event

* add comment addressing reasoning for hex encoding

* Update CHANGELOG.md

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

Co-authored-by: Alessio Treglia <alessio@tendermint.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 3, 2021
1 parent a556783 commit a9b034b
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/ibc) [\#7949](https://github.com/cosmos/cosmos-sdk/issues/7949) Standardized channel `Acknowledgement` moved to its own file. Codec registration redundancy removed.
* (crypto/types) [\#8600](https://github.com/cosmos/cosmos-sdk/pull/8600) `CompactBitArray`: optimize the `NumTrueBitsBefore` method and add an `Equal` method.
* (store/cachekv), (x/bank/types) [\#8719](https://github.com/cosmos/cosmos-sdk/pull/8719) algorithmically fix pathologically slow code
* (x/ibc) [\#8624](https://github.com/cosmos/cosmos-sdk/pull/8624) Emit full header in IBC UpdateClient message.

### Bug Fixes

Expand Down
13 changes: 13 additions & 0 deletions x/ibc/core/02-client/keeper/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper

import (
"encoding/hex"

"github.com/armon/go-metrics"

"github.com/cosmos/cosmos-sdk/telemetry"
Expand Down Expand Up @@ -95,13 +97,24 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H
)
}()

// emit the full header in events
var headerStr string
if header != nil {
// Marshal the Header as an Any and encode the resulting bytes to hex.
// This prevents the event value from containing invalid UTF-8 characters
// which may cause data to be lost when JSON encoding/decoding.
headerStr = hex.EncodeToString(types.MustMarshalHeader(k.cdc, header))

}

// emitting events in the keeper emits for both begin block and handler client updates
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeUpdateClient,
sdk.NewAttribute(types.AttributeKeyClientID, clientID),
sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()),
sdk.NewAttribute(types.AttributeKeyConsensusHeight, consensusHeight.String()),
sdk.NewAttribute(types.AttributeKeyHeader, headerStr),
),
)

Expand Down
37 changes: 37 additions & 0 deletions x/ibc/core/02-client/keeper/client_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper_test

import (
"encoding/hex"
"fmt"
"time"

Expand Down Expand Up @@ -589,3 +590,39 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
})
}
}

func (suite *KeeperTestSuite) TestUpdateClientEventEmission() {
clientID, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint)
header, err := suite.chainA.ConstructUpdateTMClientHeader(suite.chainB, clientID)
suite.Require().NoError(err)

msg, err := clienttypes.NewMsgUpdateClient(
clientID, header,
suite.chainA.SenderAccount.GetAddress(),
)

result, err := suite.chainA.SendMsgs(msg)
suite.Require().NoError(err)
// first event type is "message"
updateEvent := result.Events[1]

suite.Require().Equal(clienttypes.EventTypeUpdateClient, updateEvent.Type)

// use a boolean to ensure the update event contains the header
contains := false
for _, attr := range updateEvent.Attributes {
if string(attr.Key) == clienttypes.AttributeKeyHeader {
contains = true

bz, err := hex.DecodeString(string(attr.Value))
suite.Require().NoError(err)

emittedHeader, err := types.UnmarshalHeader(suite.chainA.App.AppCodec(), bz)
suite.Require().NoError(err)
suite.Require().Equal(header, emittedHeader)
}

}
suite.Require().True(contains)

}
33 changes: 30 additions & 3 deletions x/ibc/core/02-client/types/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func MustUnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) exported.
return consensusState
}

// MustMarshalConsensusState attempts to encode an ConsensusState object and returns the
// MustMarshalConsensusState attempts to encode a ConsensusState object and returns the
// raw encoded bytes. It panics on error.
func MustMarshalConsensusState(cdc codec.BinaryMarshaler, consensusState exported.ConsensusState) []byte {
bz, err := MarshalConsensusState(cdc, consensusState)
Expand All @@ -68,12 +68,12 @@ func MustMarshalConsensusState(cdc codec.BinaryMarshaler, consensusState exporte
return bz
}

// MarshalConsensusState protobuf serializes an ConsensusState interface
// MarshalConsensusState protobuf serializes a ConsensusState interface
func MarshalConsensusState(cdc codec.BinaryMarshaler, cs exported.ConsensusState) ([]byte, error) {
return cdc.MarshalInterface(cs)
}

// UnmarshalConsensusState returns an ConsensusState interface from raw encoded clientState
// UnmarshalConsensusState returns a ConsensusState interface from raw encoded consensus state
// bytes of a Proto-based ConsensusState type. An error is returned upon decoding
// failure.
func UnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) (exported.ConsensusState, error) {
Expand All @@ -84,3 +84,30 @@ func UnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) (exported.Con

return consensusState, nil
}

// MarshalHeader protobuf serializes a Header interface
func MarshalHeader(cdc codec.BinaryMarshaler, h exported.Header) ([]byte, error) {
return cdc.MarshalInterface(h)
}

// MustMarshalHeader attempts to encode a Header object and returns the
// raw encoded bytes. It panics on error.
func MustMarshalHeader(cdc codec.BinaryMarshaler, header exported.Header) []byte {
bz, err := MarshalHeader(cdc, header)
if err != nil {
panic(fmt.Errorf("failed to encode header: %w", err))
}

return bz
}

// UnmarshalHeader returns a Header interface from raw proto encoded header bytes.
// An error is returned upon decoding failure.
func UnmarshalHeader(cdc codec.BinaryMarshaler, bz []byte) (exported.Header, error) {
var header exported.Header
if err := cdc.UnmarshalInterface(bz, &header); err != nil {
return nil, err
}

return header, nil
}
30 changes: 30 additions & 0 deletions x/ibc/core/02-client/types/encoding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package types_test

import (
"github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
)

func (suite *TypesTestSuite) TestMarshalHeader() {

cdc := suite.chainA.App.AppCodec()
h := &ibctmtypes.Header{
TrustedHeight: types.NewHeight(4, 100),
}

// marshal header
bz, err := types.MarshalHeader(cdc, h)
suite.Require().NoError(err)

// unmarshal header
newHeader, err := types.UnmarshalHeader(cdc, bz)
suite.Require().NoError(err)

suite.Require().Equal(h, newHeader)

// use invalid bytes
invalidHeader, err := types.UnmarshalHeader(cdc, []byte("invalid bytes"))
suite.Require().Error(err)
suite.Require().Nil(invalidHeader)

}
1 change: 1 addition & 0 deletions x/ibc/core/02-client/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
AttributeKeySubjectClientID = "subject_client_id"
AttributeKeyClientType = "client_type"
AttributeKeyConsensusHeight = "consensus_height"
AttributeKeyHeader = "header"
)

// IBC client events vars
Expand Down
2 changes: 1 addition & 1 deletion x/ibc/core/spec/06_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ callbacks to IBC applications.
| update_client | client_id | {clientId} |
| update_client | client_type | {clientType} |
| update_client | consensus_height | {consensusHeight} |
| update_client | header | {header} |
| message | action | update_client |
| message | module | ibc_client |

Expand Down Expand Up @@ -238,4 +239,3 @@ callbacks to IBC applications.
| message | action | timeout_packet |
| message | module | ibc-channel |


0 comments on commit a9b034b

Please sign in to comment.