Skip to content

Commit

Permalink
ibc: commit packet and hash (cosmos#7808)
Browse files Browse the repository at this point in the history
* ibc: commit packet and hash

* minor changes

* fix build

* update err msgs

* don't use Any

* update commitment hash to used fixed length preimage

The commitment hash will now use 8 bytes timeout timestamp + 8 bytes timeout height version number + 8 bytes timeout height version height + sha 256 hash of data

* remove error from CommitPacket return values

* update godoc

* rm proto-tools-stamp

Co-authored-by: Colin Axner <[email protected]>
Co-authored-by: colin axnér <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Nov 18, 2020
1 parent 97d9661 commit 87315a6
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 38 deletions.
5 changes: 3 additions & 2 deletions x/ibc/applications/transfer/types/trace.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package types

import (
"crypto/sha256"
"encoding/hex"
"fmt"
"sort"
"strings"

"github.com/tendermint/tendermint/crypto/tmhash"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtypes "github.com/tendermint/tendermint/types"

Expand Down Expand Up @@ -42,7 +42,8 @@ func ParseDenomTrace(rawDenom string) DenomTrace {
//
// hash = sha256(tracePath + "/" + baseDenom)
func (dt DenomTrace) Hash() tmbytes.HexBytes {
return tmhash.Sum([]byte(dt.GetFullDenomPath()))
hash := sha256.Sum256([]byte(dt.GetFullDenomPath()))
return hash[:]
}

// GetPrefix returns the receiving denomination prefix composed by the trace info and a separator.
Expand Down
3 changes: 0 additions & 3 deletions x/ibc/core/02-client/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterInterface(
"ibc.core.client.v1.Height",
(*exported.Height)(nil),
)
registry.RegisterImplementations(
(*exported.Height)(nil),
&Height{},
)
registry.RegisterInterface(
Expand Down
3 changes: 2 additions & 1 deletion x/ibc/core/03-connection/keeper/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,10 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() {
packet.Data = []byte(ibctesting.InvalidID)
}

commitment := channeltypes.CommitPacket(suite.chainB.App.IBCKeeper.Codec(), packet)
err = suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketCommitment(
suite.chainB.GetContext(), connection, malleateHeight(proofHeight, tc.heightDiff), proof,
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), channeltypes.CommitPacket(packet),
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment,
)

if tc.expPass {
Expand Down
14 changes: 10 additions & 4 deletions x/ibc/core/04-channel/keeper/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ func (k Keeper) SendPacket(
)
}

commitment := types.CommitPacket(k.cdc, packet)

nextSequenceSend++
k.SetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), nextSequenceSend)
k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), types.CommitPacket(packet))
k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment)

// Emit Event with Packet data along with other packet information for relayer to pick up
// and relay to other chain
Expand Down Expand Up @@ -216,11 +218,13 @@ func (k Keeper) RecvPacket(
)
}

commitment := types.CommitPacket(k.cdc, packet)

// verify that the counterparty did commit to sending this packet
if err := k.connectionKeeper.VerifyPacketCommitment(
ctx, connectionEnd, proofHeight, proof,
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(),
types.CommitPacket(packet),
commitment,
); err != nil {
return sdkerrors.Wrap(err, "couldn't verify counterparty packet commitment")
}
Expand Down Expand Up @@ -443,9 +447,11 @@ func (k Keeper) AcknowledgePacket(

commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())

packetCommitment := types.CommitPacket(k.cdc, packet)

// verify we sent the packet and haven't cleared it out yet
if !bytes.Equal(commitment, types.CommitPacket(packet)) {
return sdkerrors.Wrapf(types.ErrInvalidPacket, "commitment bytes are not equal: got (%v), expected (%v)", types.CommitPacket(packet), commitment)
if !bytes.Equal(commitment, packetCommitment) {
return sdkerrors.Wrapf(types.ErrInvalidPacket, "commitment bytes are not equal: got (%v), expected (%v)", packetCommitment, commitment)
}

if err := k.connectionKeeper.VerifyPacketAcknowledgement(
Expand Down
12 changes: 8 additions & 4 deletions x/ibc/core/04-channel/keeper/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ func (k Keeper) TimeoutPacket(

commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())

packetCommitment := types.CommitPacket(k.cdc, packet)

// verify we sent the packet and haven't cleared it out yet
if !bytes.Equal(commitment, types.CommitPacket(packet)) {
return sdkerrors.Wrapf(types.ErrInvalidPacket, "packet commitment bytes are not equal: got (%v), expected (%v)", commitment, types.CommitPacket(packet))
if !bytes.Equal(commitment, packetCommitment) {
return sdkerrors.Wrapf(types.ErrInvalidPacket, "packet commitment bytes are not equal: got (%v), expected (%v)", commitment, packetCommitment)
}

switch channel.Ordering {
Expand Down Expand Up @@ -216,9 +218,11 @@ func (k Keeper) TimeoutOnClose(

commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())

packetCommitment := types.CommitPacket(k.cdc, packet)

// verify we sent the packet and haven't cleared it out yet
if !bytes.Equal(commitment, types.CommitPacket(packet)) {
return sdkerrors.Wrapf(types.ErrInvalidPacket, "packet commitment bytes are not equal: got (%v), expected (%v)", commitment, types.CommitPacket(packet))
if !bytes.Equal(commitment, packetCommitment) {
return sdkerrors.Wrapf(types.ErrInvalidPacket, "packet commitment bytes are not equal: got (%v), expected (%v)", commitment, packetCommitment)
}

counterpartyHops, found := k.CounterpartyHops(ctx, channel)
Expand Down
32 changes: 23 additions & 9 deletions x/ibc/core/04-channel/types/packet.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
package types

import (
"github.com/tendermint/tendermint/crypto/tmhash"
"crypto/sha256"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
)

// CommitPacket returns a packet commitment bytes. The commitment consists of:
// hash(timeout_timestamp + timeout_version_number + timeout_version_height + data) from a given packet.
func CommitPacket(packet exported.PacketI) []byte {
// CommitPacket returns the packet commitment bytes. The commitment consists of:
// sha256_hash(timeout_timestamp + timeout_height.VersionNumber + timeout_height.VersionHeight + sha256_hash(data))
// from a given packet. This results in a fixed length preimage.
// NOTE: sdk.Uint64ToBigEndian sets the uint64 to a slice of length 8.
func CommitPacket(cdc codec.BinaryMarshaler, packet exported.PacketI) []byte {
timeoutHeight := packet.GetTimeoutHeight()

buf := sdk.Uint64ToBigEndian(packet.GetTimeoutTimestamp())
buf = append(buf, sdk.Uint64ToBigEndian(packet.GetTimeoutHeight().GetVersionNumber())...)
buf = append(buf, sdk.Uint64ToBigEndian(packet.GetTimeoutHeight().GetVersionHeight())...)
buf = append(buf, packet.GetData()...)
return tmhash.Sum(buf)

versionNumber := sdk.Uint64ToBigEndian(timeoutHeight.GetVersionNumber())
buf = append(buf, versionNumber...)

versionHeight := sdk.Uint64ToBigEndian(timeoutHeight.GetVersionHeight())
buf = append(buf, versionHeight...)

dataHash := sha256.Sum256(packet.GetData())
buf = append(buf, dataHash[:]...)

hash := sha256.Sum256(buf)
return hash[:]
}

// CommitAcknowledgement returns the hash of commitment bytes
func CommitAcknowledgement(data []byte) []byte {
return tmhash.Sum(data)
hash := sha256.Sum256(data)
return hash[:]
}

var _ exported.PacketI = (*Packet)(nil)
Expand Down
16 changes: 16 additions & 0 deletions x/ibc/core/04-channel/types/packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,25 @@ import (

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
)

func TestCommitPacket(t *testing.T) {
packet := types.NewPacket(validPacketData, 1, portid, chanid, cpportid, cpchanid, timeoutHeight, timeoutTimestamp)

registry := codectypes.NewInterfaceRegistry()
clienttypes.RegisterInterfaces(registry)
types.RegisterInterfaces(registry)

cdc := codec.NewProtoCodec(registry)

commitment := types.CommitPacket(cdc, &packet)
require.NotNil(t, commitment)
}

func TestPacketValidateBasic(t *testing.T) {
testCases := []struct {
packet types.Packet
Expand Down
31 changes: 16 additions & 15 deletions x/ibc/light-clients/07-tendermint/types/client_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,57 +33,57 @@ func (suite *TendermintTestSuite) TestValidate() {
}{
{
name: "valid client",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: true,
},
{
name: "valid client with nil upgrade path",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), "", false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), "", false, false),
expPass: true,
},
{
name: "invalid chainID",
clientState: types.NewClientState(" ", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(" ", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "invalid trust level",
clientState: types.NewClientState(chainID, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "invalid trusting period",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "invalid unbonding period",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "invalid max clock drift",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "invalid height",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "trusting period not less than unbonding period",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
expPass: false,
},
{
name: "proof specs is nil",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, nil, upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, nil, upgradePath, false, false),
expPass: false,
},
{
name: "proof specs contains nil",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, []*ics23.ProofSpec{ics23.TendermintSpec, nil}, upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, []*ics23.ProofSpec{ics23.TendermintSpec, nil}, upgradePath, false, false),
expPass: false,
},
}
Expand Down Expand Up @@ -119,7 +119,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
// },
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
consensusState: types.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()),
},
Expand All @@ -128,7 +128,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
},
{
name: "latest client height < height",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
consensusState: types.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()),
},
Expand All @@ -146,7 +146,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
},
{
name: "proof verification failed",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false),
consensusState: types.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()),
NextValidatorsHash: suite.valsHash,
Expand Down Expand Up @@ -396,9 +396,10 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {

store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)

commitment := channeltypes.CommitPacket(suite.chainA.App.IBCKeeper.Codec(), packet)
err = clientState.VerifyPacketCommitment(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), channeltypes.CommitPacket(packet),
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment,
)

if tc.expPass {
Expand Down

0 comments on commit 87315a6

Please sign in to comment.