ibc: commit packet and hash (#7808)

* 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 <colinaxner@berkeley.edu>
Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Federico Kunze 2020-11-18 20:01:22 +01:00 committed by GitHub
parent 97d96612c9
commit 87315a6aab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 38 deletions

View File

@ -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"
@ -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.

View File

@ -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(

View File

@ -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 {

View File

@ -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
@ -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")
}
@ -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(

View File

@ -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 {
@ -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)

View File

@ -1,8 +1,9 @@
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"
@ -10,19 +11,32 @@ import (
"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)

View File

@ -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

View File

@ -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,
},
}
@ -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()),
},
@ -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()),
},
@ -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,
@ -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 {