diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index abdad3fd002..d3807b1f104 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -7,6 +7,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" "github.com/cosmos/ibc-go/v3/modules/core/exported" ) @@ -31,9 +35,27 @@ func (k Keeper) VerifyClientState( return sdkerrors.Wrapf(clienttypes.ErrClientStateNotFound, "client (%s) status is %s", clientID, status) } - if err := targetClient.VerifyClientState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetPrefix(), connection.GetCounterparty().GetClientID(), proof, clientState); err != nil { + merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(connection.GetCounterparty().GetClientID())) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + bz, err := k.cdc.MarshalInterface(clientState) + if err != nil { + return err + } + + if err := targetClient.VerifyMembership( + ctx, clientStore, k.cdc, height, + 0, 0, // skip delay period checks for non-packet processing verification + proof, path, bz, + ); err != nil { return sdkerrors.Wrapf(err, "failed client state verification for target client: %s", clientID) } @@ -62,9 +84,26 @@ func (k Keeper) VerifyClientConsensusState( return sdkerrors.Wrapf(clienttypes.ErrClientStateNotFound, "client (%s) status is %s", clientID, status) } - if err := clientState.VerifyClientConsensusState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState, + merklePath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(connection.GetCounterparty().GetClientID(), consensusHeight)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + bz, err := k.cdc.MarshalInterface(consensusState) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( + ctx, clientStore, k.cdc, height, + 0, 0, // skip delay period checks for non-packet processing verification + proof, path, bz, ); err != nil { return sdkerrors.Wrapf(err, "failed consensus state verification for client (%s)", clientID) } @@ -80,7 +119,7 @@ func (k Keeper) VerifyConnectionState( height exported.Height, proof []byte, connectionID string, - connectionEnd exported.ConnectionI, // opposite connection + counterpartyConnection exported.ConnectionI, // opposite connection ) error { clientID := connection.GetClientID() clientStore := k.clientKeeper.ClientStore(ctx, clientID) @@ -94,9 +133,31 @@ func (k Keeper) VerifyConnectionState( return sdkerrors.Wrapf(clienttypes.ErrClientStateNotFound, "client (%s) status is %s", clientID, status) } - if err := clientState.VerifyConnectionState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetPrefix(), proof, connectionID, connectionEnd, + merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + connectionEnd, ok := counterpartyConnection.(connectiontypes.ConnectionEnd) + if !ok { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid connection type %T", counterpartyConnection) + } + + bz, err := k.cdc.Marshal(&connectionEnd) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( + ctx, clientStore, k.cdc, height, + 0, 0, // skip delay period checks for non-packet processing verification + proof, path, bz, ); err != nil { return sdkerrors.Wrapf(err, "failed connection state verification for client (%s)", clientID) } @@ -127,10 +188,31 @@ func (k Keeper) VerifyChannelState( return sdkerrors.Wrapf(clienttypes.ErrClientStateNotFound, "client (%s) status is %s", clientID, status) } - if err := clientState.VerifyChannelState( - clientStore, k.cdc, height, - connection.GetCounterparty().GetPrefix(), proof, - portID, channelID, channel, + merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + channelEnd, ok := channel.(channeltypes.Channel) + if !ok { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid channel type %T", channel) + } + + bz, err := k.cdc.Marshal(&channelEnd) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( + ctx, clientStore, k.cdc, height, + 0, 0, // skip delay period checks for non-packet processing verification + proof, path, bz, ); err != nil { return sdkerrors.Wrapf(err, "failed channel state verification for client (%s)", clientID) } @@ -166,11 +248,21 @@ func (k Keeper) VerifyPacketCommitment( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyPacketCommitment( + merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - sequence, commitmentBytes, + proof, path, commitmentBytes, ); err != nil { return sdkerrors.Wrapf(err, "failed packet commitment verification for client (%s)", clientID) } @@ -206,11 +298,21 @@ func (k Keeper) VerifyPacketAcknowledgement( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyPacketAcknowledgement( + merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - sequence, acknowledgement, + proof, path, channeltypes.CommitAcknowledgement(acknowledgement), ); err != nil { return sdkerrors.Wrapf(err, "failed packet acknowledgement verification for client (%s)", clientID) } @@ -246,11 +348,21 @@ func (k Keeper) VerifyPacketReceiptAbsence( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyPacketReceiptAbsence( + merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyNonMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - sequence, + proof, path, ); err != nil { return sdkerrors.Wrapf(err, "failed packet receipt absence verification for client (%s)", clientID) } @@ -285,11 +397,21 @@ func (k Keeper) VerifyNextSequenceRecv( timeDelay := connection.GetDelayPeriod() blockDelay := k.getBlockDelay(ctx, connection) - if err := clientState.VerifyNextSequenceRecv( + merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) + merklePath, err := commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath) + if err != nil { + return err + } + + path, err := k.cdc.Marshal(&merklePath) + if err != nil { + return err + } + + if err := clientState.VerifyMembership( ctx, clientStore, k.cdc, height, timeDelay, blockDelay, - connection.GetCounterparty().GetPrefix(), proof, portID, channelID, - nextSequenceRecv, + proof, path, sdk.Uint64ToBigEndian(nextSequenceRecv), ); err != nil { return sdkerrors.Wrapf(err, "failed next sequence receive verification for client (%s)", clientID) } diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index f71715aa6c5..9d54a66c71b 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -122,98 +122,6 @@ type ClientState interface { path []byte, ) error - VerifyClientState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - prefix Prefix, - counterpartyClientIdentifier string, - proof []byte, - clientState ClientState, - ) error - VerifyClientConsensusState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - counterpartyClientIdentifier string, - consensusHeight Height, - prefix Prefix, - proof []byte, - consensusState ConsensusState, - ) error - VerifyConnectionState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - prefix Prefix, - proof []byte, - connectionID string, - connectionEnd ConnectionI, - ) error - VerifyChannelState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - prefix Prefix, - proof []byte, - portID, - channelID string, - channel ChannelI, - ) error - VerifyPacketCommitment( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - commitmentBytes []byte, - ) error - VerifyPacketAcknowledgement( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - acknowledgement []byte, - ) error - VerifyPacketReceiptAbsence( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - ) error - VerifyNextSequenceRecv( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix Prefix, - proof []byte, - portID, - channelID string, - nextSequenceRecv uint64, - ) error GetTimestampAtHeight( ctx sdk.Context, clientStore sdk.KVStore, diff --git a/modules/light-clients/07-tendermint/types/client_state.go b/modules/light-clients/07-tendermint/types/client_state.go index 029f8da0932..1593f76c959 100644 --- a/modules/light-clients/07-tendermint/types/client_state.go +++ b/modules/light-clients/07-tendermint/types/client_state.go @@ -12,10 +12,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" "github.com/cosmos/ibc-go/v3/modules/core/exported" ) @@ -205,333 +202,6 @@ func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientSto return nil } -// VerifyClientState verifies a proof of the client state of the running chain -// stored on the target machine -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyClientState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - counterpartyClientIdentifier string, - proof []byte, - clientState exported.ClientState, -) error { - merkleProof, provingConsensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - clientPrefixedPath := commitmenttypes.NewMerklePath(host.FullClientStatePath(counterpartyClientIdentifier)) - path, err := commitmenttypes.ApplyPrefix(prefix, clientPrefixedPath) - if err != nil { - return err - } - - if clientState == nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidClient, "client state cannot be empty") - } - - _, ok := clientState.(*ClientState) - if !ok { - return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "invalid client type %T, expected %T", clientState, &ClientState{}) - } - - bz, err := cdc.MarshalInterface(clientState) - if err != nil { - return err - } - - return merkleProof.VerifyMembership(cs.ProofSpecs, provingConsensusState.GetRoot(), path, bz) -} - -// VerifyClientConsensusState verifies a proof of the consensus state of the -// Tendermint client stored on the target machine. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyClientConsensusState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - counterpartyClientIdentifier string, - consensusHeight exported.Height, - prefix exported.Prefix, - proof []byte, - consensusState exported.ConsensusState, -) error { - merkleProof, provingConsensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - clientPrefixedPath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(counterpartyClientIdentifier, consensusHeight)) - path, err := commitmenttypes.ApplyPrefix(prefix, clientPrefixedPath) - if err != nil { - return err - } - - if consensusState == nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be empty") - } - - _, ok := consensusState.(*ConsensusState) - if !ok { - return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid consensus type %T, expected %T", consensusState, &ConsensusState{}) - } - - bz, err := cdc.MarshalInterface(consensusState) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, provingConsensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// VerifyConnectionState verifies a proof of the connection state of the -// specified connection end stored on the target machine. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyConnectionState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - proof []byte, - connectionID string, - connectionEnd exported.ConnectionI, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - connectionPath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) - path, err := commitmenttypes.ApplyPrefix(prefix, connectionPath) - if err != nil { - return err - } - - connection, ok := connectionEnd.(connectiontypes.ConnectionEnd) - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid connection type %T", connectionEnd) - } - - bz, err := cdc.Marshal(&connection) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// VerifyChannelState verifies a proof of the channel state of the specified -// channel end, under the specified port, stored on the target machine. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyChannelState( - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - channel exported.ChannelI, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - channelPath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) - path, err := commitmenttypes.ApplyPrefix(prefix, channelPath) - if err != nil { - return err - } - - channelEnd, ok := channel.(channeltypes.Channel) - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid channel type %T", channel) - } - - bz, err := cdc.Marshal(&channelEnd) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - -// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at -// the specified port, specified channel, and specified sequence. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyPacketCommitment( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - commitmentBytes []byte, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, commitmentPath) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, commitmentBytes); err != nil { - return err - } - - return nil -} - -// VerifyPacketAcknowledgement verifies a proof of an incoming packet -// acknowledgement at the specified port, specified channel, and specified sequence. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyPacketAcknowledgement( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, - acknowledgement []byte, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, ackPath) - if err != nil { - return err - } - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, channeltypes.CommitAcknowledgement(acknowledgement)); err != nil { - return err - } - - return nil -} - -// VerifyPacketReceiptAbsence verifies a proof of the absence of an -// incoming packet receipt at the specified port, specified channel, and -// specified sequence. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyPacketReceiptAbsence( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - sequence uint64, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence)) - path, err := commitmenttypes.ApplyPrefix(prefix, receiptPath) - if err != nil { - return err - } - - if err := merkleProof.VerifyNonMembership(cs.ProofSpecs, consensusState.GetRoot(), path); err != nil { - return err - } - - return nil -} - -// VerifyNextSequenceRecv verifies a proof of the next sequence number to be -// received of the specified channel at the specified port. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (cs ClientState) VerifyNextSequenceRecv( - ctx sdk.Context, - store sdk.KVStore, - cdc codec.BinaryCodec, - height exported.Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - prefix exported.Prefix, - proof []byte, - portID, - channelID string, - nextSequenceRecv uint64, -) error { - merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof) - if err != nil { - return err - } - - // check delay period has passed - if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { - return err - } - - nextSequenceRecvPath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) - path, err := commitmenttypes.ApplyPrefix(prefix, nextSequenceRecvPath) - if err != nil { - return err - } - - bz := sdk.Uint64ToBigEndian(nextSequenceRecv) - - if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil { - return err - } - - return nil -} - // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). func (cs ClientState) VerifyMembership( @@ -663,47 +333,3 @@ func verifyDelayPeriodPassed(ctx sdk.Context, store sdk.KVStore, proofHeight exp return nil } - -// produceVerificationArgs perfoms the basic checks on the arguments that are -// shared between the verification functions and returns the unmarshalled -// merkle proof, the consensus state and an error if one occurred. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func produceVerificationArgs( - store sdk.KVStore, - cdc codec.BinaryCodec, - cs ClientState, - height exported.Height, - prefix exported.Prefix, - proof []byte, -) (merkleProof commitmenttypes.MerkleProof, consensusState *ConsensusState, err error) { - if cs.GetLatestHeight().LT(height) { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrapf( - sdkerrors.ErrInvalidHeight, - "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, - ) - } - - if prefix == nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidPrefix, "prefix cannot be empty") - } - - _, ok := prefix.(*commitmenttypes.MerklePrefix) - if !ok { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidPrefix, "invalid prefix type %T, expected *MerklePrefix", prefix) - } - - if proof == nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof cannot be empty") - } - - if err = cdc.Unmarshal(proof, &merkleProof); err != nil { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into commitment merkle proof") - } - - consensusState, found := GetConsensusState(store, cdc, height) - if !found { - return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(clienttypes.ErrConsensusStateNotFound, "please ensure the proof was constructed against a height that exists on the client") - } - - return merkleProof, consensusState, nil -} diff --git a/modules/light-clients/07-tendermint/types/client_state_test.go b/modules/light-clients/07-tendermint/types/client_state_test.go index 0a46d6dd7f0..56bbf0909b3 100644 --- a/modules/light-clients/07-tendermint/types/client_state_test.go +++ b/modules/light-clients/07-tendermint/types/client_state_test.go @@ -18,12 +18,6 @@ import ( ) const ( - testClientID = "clientidone" - testConnectionID = "connectionid" - testPortID = "testportid" - testChannelID = "testchannelid" - testSequence = 1 - // Do not change the length of these variables fiftyCharChainID = "12345678901234567890123456789012345678901234567890" fiftyOneCharChainID = "123456789012345678901234567890123456789012345678901" @@ -704,736 +698,3 @@ func (suite *TendermintTestSuite) TestVerifyNonMembership() { }) } } - -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { - testCases := []struct { - name string - clientState *types.ClientState - consensusState *types.ConsensusState - prefix commitmenttypes.MerklePrefix - proof []byte - expPass bool - }{ - // FIXME: uncomment - // { - // name: "successful verification", - // clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - // consensusState: types.ConsensusState{ - // Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), - // }, - // prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), - // expPass: true, - // }, - { - name: "ApplyPrefix failed", - 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()), - }, - prefix: commitmenttypes.MerklePrefix{}, - expPass: false, - }, - { - name: "latest client height < height", - 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()), - }, - prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), - expPass: false, - }, - { - name: "proof verification failed", - 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, - }, - prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), - proof: []byte{}, - expPass: false, - }, - } - - for i, tc := range testCases { - tc := tc - - err := tc.clientState.VerifyClientConsensusState( - nil, suite.cdc, height, "chainA", tc.clientState.LatestHeight, tc.prefix, tc.proof, tc.consensusState, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - } - } -} - -// test verification of the connection on chainB being represented in the -// light client on chainA -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (suite *TendermintTestSuite) TestVerifyConnectionState() { - var ( - clientState *types.ClientState - proof []byte - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - connection := path.EndpointB.GetConnection() - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make connection proof - connectionKey := host.ConnectionKey(path.EndpointB.ConnectionID) - proof, proofHeight = suite.chainB.QueryProof(connectionKey) - - tc.malleate() // make changes as necessary - - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - - err := clientState.VerifyConnectionState( - store, suite.chainA.Codec, proofHeight, &prefix, proof, path.EndpointB.ConnectionID, connection, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the channel on chainB being represented in the light -// client on chainA -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (suite *TendermintTestSuite) TestVerifyChannelState() { - var ( - clientState *types.ClientState - proof []byte - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - channel := path.EndpointB.GetChannel() - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make channel proof - channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - proof, proofHeight = suite.chainB.QueryProof(channelKey) - - tc.malleate() // make changes as necessary - - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - - err := clientState.VerifyChannelState( - store, suite.chainA.Codec, proofHeight, &prefix, proof, - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the packet commitment on chainB being represented -// in the light client on chainA. A send from chainB to chainA is simulated. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 1000 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - err := path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make packet commitment proof - packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - proof, proofHeight = path.EndpointB.QueryProof(packetKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - commitment := channeltypes.CommitPacket(suite.chainA.App.GetIBCKeeper().Codec(), packet) - err = clientState.VerifyPacketCommitment( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the acknowledgement on chainB being represented -// in the light client on chainA. A send and ack from chainA to chainB -// is simulated. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 10 - }, - expPass: false, - }, - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - - // send packet - err := path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - // write receipt and ack - err = path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make packet acknowledgement proof - acknowledgementKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proof, proofHeight = suite.chainB.QueryProof(acknowledgementKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - err = clientState.VerifyPacketAcknowledgement( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibcmock.MockAcknowledgement.Acknowledgement(), - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the absent acknowledgement on chainB being represented -// in the light client on chainA. A send from chainB to chainA is simulated, but -// no receive. -func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 10 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - - // send packet, but no recv - err := path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make packet receipt absence proof - receiptKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proof, proofHeight = path.EndpointB.QueryProof(receiptKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - err = clientState.VerifyPacketReceiptAbsence( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// test verification of the next receive sequence on chainB being represented -// in the light client on chainA. A send and receive from chainB to chainA is -// simulated. -// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294 -func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { - var ( - clientState *types.ClientState - proof []byte - delayTimePeriod uint64 - delayBlockPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "successful verification", func() {}, true, - }, - { - name: "delay time period has passed", - malleate: func() { - delayTimePeriod = uint64(time.Second.Nanoseconds()) - }, - expPass: true, - }, - { - name: "delay time period has not passed", - malleate: func() { - delayTimePeriod = uint64(time.Hour.Nanoseconds()) - }, - expPass: false, - }, - { - name: "delay block period has passed", - malleate: func() { - delayBlockPeriod = 1 - }, - expPass: true, - }, - { - name: "delay block period has not passed", - malleate: func() { - delayBlockPeriod = 10 - }, - expPass: false, - }, - - { - "ApplyPrefix failed", func() { - prefix = commitmenttypes.MerklePrefix{} - }, false, - }, - { - "latest client height < height", func() { - proofHeight = clientState.LatestHeight.Increment() - }, false, - }, - { - "proof verification failed", func() { - proof = invalidProof - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - // setup testing conditions - path := ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetChannelOrdered() - suite.coordinator.Setup(path) - packet := channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - - // send packet - err := path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - // next seq recv incremented - err = path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - - var ok bool - clientStateI := suite.chainA.GetClientState(path.EndpointA.ClientID) - clientState, ok = clientStateI.(*types.ClientState) - suite.Require().True(ok) - - prefix = suite.chainB.GetPrefix() - - // make next seq recv proof - nextSeqRecvKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - proof, proofHeight = suite.chainB.QueryProof(nextSeqRecvKey) - - // reset time and block delays to 0, malleate may change to a specific non-zero value. - delayTimePeriod = 0 - delayBlockPeriod = 0 - tc.malleate() // make changes as necessary - - ctx := suite.chainA.GetContext() - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - - err = clientState.VerifyNextSequenceRecv( - ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()+1, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *TendermintTestSuite) TestGetTimestampAtHeight() { - suite.SetupTest() - - path := ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetChannelOrdered() - suite.coordinator.Setup(path) - - ctx := suite.chainA.GetContext() - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - clientState := path.EndpointA.GetClientState() - - testCases := []struct { - name string - height exported.Height - expValue uint64 - expPass bool - }{ - { - name: "get timestamp at height exists", - height: clientState.GetLatestHeight(), - expValue: path.EndpointA.GetConsensusState(clientState.GetLatestHeight()).GetTimestamp(), - expPass: true, - }, - { - name: "get timestamp at height not exists", - height: clientState.GetLatestHeight().Increment(), - }, - } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - ts, err := clientState.GetTimestampAtHeight( - ctx, clientStore, suite.chainA.Codec, tc.height, - ) - - suite.Require().Equal(tc.expValue, ts) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -}