ConsensusState is retrieved by light clients in verifyXYZ as necessary (#7005)

* move con state retrieval to verify funcs

* refactor tm client state tests

* fix build

* Apply suggestions from code review

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

* apply @fedekunze review comments

* apply @AdityaSripal review comment

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Aditya <adityasripal@gmail.com>
This commit is contained in:
colin axnér 2020-08-12 11:20:29 +02:00 committed by GitHub
parent 308c879b11
commit d752a7b21f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 578 additions and 497 deletions

View File

@ -46,7 +46,6 @@ type ClientState interface {
proof []byte,
connectionID string,
connectionEnd connectionexported.ConnectionI,
consensusState ConsensusState,
) error
VerifyChannelState(
store sdk.KVStore,
@ -57,7 +56,6 @@ type ClientState interface {
portID,
channelID string,
channel channelexported.ChannelI,
consensusState ConsensusState,
) error
VerifyPacketCommitment(
store sdk.KVStore,
@ -69,7 +67,6 @@ type ClientState interface {
channelID string,
sequence uint64,
commitmentBytes []byte,
consensusState ConsensusState,
) error
VerifyPacketAcknowledgement(
store sdk.KVStore,
@ -81,7 +78,6 @@ type ClientState interface {
channelID string,
sequence uint64,
acknowledgement []byte,
consensusState ConsensusState,
) error
VerifyPacketAcknowledgementAbsence(
store sdk.KVStore,
@ -92,7 +88,6 @@ type ClientState interface {
portID,
channelID string,
sequence uint64,
consensusState ConsensusState,
) error
VerifyNextSequenceRecv(
store sdk.KVStore,
@ -103,7 +98,6 @@ type ClientState interface {
portID,
channelID string,
nextSequenceRecv uint64,
consensusState ConsensusState,
) error
}

View File

@ -34,7 +34,7 @@ func (k Keeper) VerifyClientConsensusState(
k.clientKeeper.ClientStore(ctx, clientID), k.cdc, targetConsState.GetRoot(), height,
connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState,
); err != nil {
return sdkerrors.Wrap(err, "failed consensus state verification")
return sdkerrors.Wrapf(err, "failed consensus state verification for client (%s)", connection.GetClientID())
}
return nil
@ -55,22 +55,11 @@ func (k Keeper) VerifyConnectionState(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
if err := clientState.VerifyConnectionState(
k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height,
connection.GetCounterparty().GetPrefix(), proof, connectionID, connectionEnd, consensusState,
connection.GetCounterparty().GetPrefix(), proof, connectionID, connectionEnd,
); err != nil {
return sdkerrors.Wrap(err, "failed connection state verification")
return sdkerrors.Wrapf(err, "failed connection state verification for client (%s)", connection.GetClientID())
}
return nil
@ -92,23 +81,12 @@ func (k Keeper) VerifyChannelState(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
if err := clientState.VerifyChannelState(
k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height,
connection.GetCounterparty().GetPrefix(), proof,
portID, channelID, channel, consensusState,
portID, channelID, channel,
); err != nil {
return sdkerrors.Wrap(err, "failed channel state verification")
return sdkerrors.Wrapf(err, "failed channel state verification for client (%s)", connection.GetClientID())
}
return nil
@ -131,23 +109,12 @@ func (k Keeper) VerifyPacketCommitment(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
if err := clientState.VerifyPacketCommitment(
k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height,
connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
sequence, commitmentBytes, consensusState,
sequence, commitmentBytes,
); err != nil {
return sdkerrors.Wrap(err, "failed packet commitment verification")
return sdkerrors.Wrapf(err, "failed packet commitment verification for client (%s)", connection.GetClientID())
}
return nil
@ -170,23 +137,12 @@ func (k Keeper) VerifyPacketAcknowledgement(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
if err := clientState.VerifyPacketAcknowledgement(
k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height,
connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
sequence, acknowledgement, consensusState,
sequence, acknowledgement,
); err != nil {
return sdkerrors.Wrap(err, "failed packet acknowledgement verification")
return sdkerrors.Wrapf(err, "failed packet acknowledgement verification for client (%s)", connection.GetClientID())
}
return nil
@ -209,23 +165,12 @@ func (k Keeper) VerifyPacketAcknowledgementAbsence(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
if err := clientState.VerifyPacketAcknowledgementAbsence(
k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height,
connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
sequence, consensusState,
sequence,
); err != nil {
return sdkerrors.Wrap(err, "failed packet acknowledgement absence verification")
return sdkerrors.Wrapf(err, "failed packet acknowledgement absence verification for client (%s)", connection.GetClientID())
}
return nil
@ -247,23 +192,12 @@ func (k Keeper) VerifyNextSequenceRecv(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID())
}
// TODO: move to specific clients; blocked by #5502
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
if err := clientState.VerifyNextSequenceRecv(
k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height,
connection.GetCounterparty().GetPrefix(), proof, portID, channelID,
nextSequenceRecv, consensusState,
nextSequenceRecv,
); err != nil {
return sdkerrors.Wrap(err, "failed next sequence receive verification")
return sdkerrors.Wrapf(err, "failed next sequence receive verification for client (%s)", connection.GetClientID())
}
return nil

View File

@ -123,7 +123,7 @@ func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec {
// VerifyClientConsensusState verifies a proof of the consensus state of the
// Tendermint client stored on the target machine.
func (cs ClientState) VerifyClientConsensusState(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
provingRoot commitmentexported.Root,
height uint64,
@ -133,7 +133,7 @@ func (cs ClientState) VerifyClientConsensusState(
proof []byte,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, _, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -144,6 +144,15 @@ func (cs ClientState) VerifyClientConsensusState(
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 := codec.MarshalAny(cdc, consensusState)
if err != nil {
return err
@ -159,16 +168,15 @@ func (cs ClientState) VerifyClientConsensusState(
// VerifyConnectionState verifies a proof of the connection state of the
// specified connection end stored on the target machine.
func (cs ClientState) VerifyConnectionState(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
height uint64,
prefix commitmentexported.Prefix,
proof []byte,
connectionID string,
connectionEnd connectionexported.ConnectionI,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -198,7 +206,7 @@ func (cs ClientState) VerifyConnectionState(
// VerifyChannelState verifies a proof of the channel state of the specified
// channel end, under the specified port, stored on the target machine.
func (cs ClientState) VerifyChannelState(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
height uint64,
prefix commitmentexported.Prefix,
@ -206,9 +214,8 @@ func (cs ClientState) VerifyChannelState(
portID,
channelID string,
channel channelexported.ChannelI,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -238,7 +245,7 @@ func (cs ClientState) VerifyChannelState(
// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at
// the specified port, specified channel, and specified sequence.
func (cs ClientState) VerifyPacketCommitment(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
height uint64,
prefix commitmentexported.Prefix,
@ -247,9 +254,8 @@ func (cs ClientState) VerifyPacketCommitment(
channelID string,
sequence uint64,
commitmentBytes []byte,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -269,7 +275,7 @@ func (cs ClientState) VerifyPacketCommitment(
// VerifyPacketAcknowledgement verifies a proof of an incoming packet
// acknowledgement at the specified port, specified channel, and specified sequence.
func (cs ClientState) VerifyPacketAcknowledgement(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
height uint64,
prefix commitmentexported.Prefix,
@ -278,9 +284,8 @@ func (cs ClientState) VerifyPacketAcknowledgement(
channelID string,
sequence uint64,
acknowledgement []byte,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -301,7 +306,7 @@ func (cs ClientState) VerifyPacketAcknowledgement(
// incoming packet acknowledgement at the specified port, specified channel, and
// specified sequence.
func (cs ClientState) VerifyPacketAcknowledgementAbsence(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
height uint64,
prefix commitmentexported.Prefix,
@ -309,9 +314,8 @@ func (cs ClientState) VerifyPacketAcknowledgementAbsence(
portID,
channelID string,
sequence uint64,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -331,7 +335,7 @@ func (cs ClientState) VerifyPacketAcknowledgementAbsence(
// VerifyNextSequenceRecv verifies a proof of the next sequence number to be
// received of the specified channel at the specified port.
func (cs ClientState) VerifyNextSequenceRecv(
_ sdk.KVStore,
store sdk.KVStore,
cdc codec.BinaryMarshaler,
height uint64,
prefix commitmentexported.Prefix,
@ -339,9 +343,8 @@ func (cs ClientState) VerifyNextSequenceRecv(
portID,
channelID string,
nextSequenceRecv uint64,
consensusState clientexported.ConsensusState,
) error {
merkleProof, err := sanitizeVerificationArgs(cdc, cs, height, prefix, proof, consensusState)
merkleProof, consensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -360,53 +363,49 @@ func (cs ClientState) VerifyNextSequenceRecv(
return nil
}
// sanitizeVerificationArgs perfoms the basic checks on the arguments that are
// produceVerificationArgs perfoms the basic checks on the arguments that are
// shared between the verification functions and returns the unmarshalled
// merkle proof and an error if one occurred.
func sanitizeVerificationArgs(
// merkle proof, the consensus state and an error if one occurred.
func produceVerificationArgs(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
cs ClientState,
height uint64,
prefix commitmentexported.Prefix,
proof []byte,
consensusState clientexported.ConsensusState,
) (merkleProof commitmenttypes.MerkleProof, err error) {
) (merkleProof commitmenttypes.MerkleProof, consensusState *ConsensusState, err error) {
if cs.GetLatestHeight() < height {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrapf(
return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrapf(
sdkerrors.ErrInvalidHeight,
"client state height < proof height (%d < %d)", cs.GetLatestHeight(), height,
)
}
if cs.IsFrozen() && cs.FrozenHeight <= height {
return commitmenttypes.MerkleProof{}, clienttypes.ErrClientFrozen
return commitmenttypes.MerkleProof{}, nil, clienttypes.ErrClientFrozen
}
if prefix == nil {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrap(commitmenttypes.ErrInvalidPrefix, "prefix cannot be empty")
return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidPrefix, "prefix cannot be empty")
}
_, ok := prefix.(*commitmenttypes.MerklePrefix)
if !ok {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrapf(commitmenttypes.ErrInvalidPrefix, "invalid prefix type %T, expected *MerklePrefix", prefix)
return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidPrefix, "invalid prefix type %T, expected *MerklePrefix", prefix)
}
if proof == nil {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof cannot be empty")
return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof cannot be empty")
}
if err = cdc.UnmarshalBinaryBare(proof, &merkleProof); err != nil {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into commitment merkle proof")
return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into commitment merkle proof")
}
if consensusState == nil {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be empty")
consensusState, err = GetConsensusState(store, cdc, height)
if err != nil {
return commitmenttypes.MerkleProof{}, nil, err
}
_, ok = consensusState.(*ConsensusState)
if !ok {
return commitmenttypes.MerkleProof{}, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid consensus type %T, expected %T", consensusState, &ConsensusState{})
}
return merkleProof, nil
return merkleProof, consensusState, nil
}

View File

@ -3,11 +3,13 @@ package types_test
import (
ics23 "github.com/confio/ics23/go"
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
"github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
const (
@ -18,6 +20,10 @@ const (
testSequence = 1
)
var (
invalidProof = []byte("invalid proof")
)
func (suite *TendermintTestSuite) TestValidate() {
testCases := []struct {
name string
@ -160,478 +166,506 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
}
}
// test verification of the connection on chainB being represented in the
// light client on chainA
func (suite *TendermintTestSuite) TestVerifyConnectionState() {
counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, commitmenttypes.NewMerklePrefix([]byte("ibc")))
conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []string{"1.0.0"})
var (
clientState *types.ClientState
proof []byte
proofHeight uint64
prefix commitmenttypes.MerklePrefix
)
testCases := []struct {
name string
clientState *ibctmtypes.ClientState
connection connectiontypes.ConnectionEnd
consensusState ibctmtypes.ConsensusState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
name string
malleate func()
expPass bool
}{
// FIXME: uncomment
// {
// name: "successful verification",
// clientState: ibctmtypes.NewClientState(chainID, chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
// connection: conn,
// consensusState: ibctmtypes.ConsensusState{
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
// },
// prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
// expPass: true,
// },
{
name: "ApplyPrefix failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
connection: conn,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
"successful verification", func() {}, true,
},
{
name: "latest client height < height",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
connection: conn,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"ApplyPrefix failed", func() {
prefix = commitmenttypes.MerklePrefix{}
}, false,
},
{
name: "client is frozen",
clientState: &ibctmtypes.ClientState{LatestHeight: height, FrozenHeight: height - 1},
connection: conn,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"latest client height < height", func() {
proofHeight = clientState.LatestHeight + 1
}, false,
},
{
name: "proof verification failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
connection: conn,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
NextValidatorsHash: suite.valsHash,
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
"client is frozen", func() {
clientState.FrozenHeight = 1
}, false,
},
{
"proof verification failed", func() {
proof = invalidProof
}, false,
},
}
for i, tc := range testCases {
for _, tc := range testCases {
tc := tc
err := tc.clientState.VerifyConnectionState(
nil, suite.cdc, height, tc.prefix, tc.proof, testConnectionID, tc.connection, tc.consensusState,
)
suite.Run(tc.name, func() {
suite.SetupTest() // reset
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)
}
// setup testing conditions
clientA, _, _, connB, _, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
connection := suite.chainB.GetConnection(connB)
var ok bool
clientStateI := suite.chainA.GetClientState(clientA)
clientState, ok = clientStateI.(*types.ClientState)
suite.Require().True(ok)
prefix = suite.chainB.GetPrefix()
// make connection proof
connectionKey := host.KeyConnection(connB.ID)
proof, proofHeight = suite.chainB.QueryProof(connectionKey)
tc.malleate() // make changes as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
err := clientState.VerifyConnectionState(
store, suite.chainA.Codec, proofHeight, &prefix, proof, connB.ID, 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
func (suite *TendermintTestSuite) TestVerifyChannelState() {
counterparty := channeltypes.NewCounterparty(testPortID, testChannelID)
ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, counterparty, []string{testConnectionID}, "1.0.0")
var (
clientState *types.ClientState
proof []byte
proofHeight uint64
prefix commitmenttypes.MerklePrefix
)
testCases := []struct {
name string
clientState *ibctmtypes.ClientState
channel channeltypes.Channel
consensusState ibctmtypes.ConsensusState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
name string
malleate func()
expPass bool
}{
// FIXME: uncomment
// {
// name: "successful verification",
// clientState: ibctmtypes.NewClientState(chainID, height, commitmenttypes.GetSDKSpecs()),
// connection: conn,
// consensusState: ibctmtypes.ConsensusState{
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
// },
// prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
// expPass: true,
// },
{
name: "ApplyPrefix failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
channel: ch,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
"successful verification", func() {}, true,
},
{
name: "latest client height < height",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
channel: ch,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"ApplyPrefix failed", func() {
prefix = commitmenttypes.MerklePrefix{}
}, false,
},
{
name: "client is frozen",
clientState: &ibctmtypes.ClientState{LatestHeight: height, FrozenHeight: height - 1},
channel: ch,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"latest client height < height", func() {
proofHeight = clientState.LatestHeight + 1
}, false,
},
{
name: "proof verification failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
channel: ch,
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
NextValidatorsHash: suite.valsHash,
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
"client is frozen", func() {
clientState.FrozenHeight = 1
}, false,
},
{
"proof verification failed", func() {
proof = invalidProof
}, false,
},
}
for i, tc := range testCases {
for _, tc := range testCases {
tc := tc
err := tc.clientState.VerifyChannelState(
nil, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, &tc.channel, tc.consensusState,
)
suite.Run(tc.name, func() {
suite.SetupTest() // reset
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)
}
// setup testing conditions
clientA, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
channel := suite.chainB.GetChannel(channelB)
var ok bool
clientStateI := suite.chainA.GetClientState(clientA)
clientState, ok = clientStateI.(*types.ClientState)
suite.Require().True(ok)
prefix = suite.chainB.GetPrefix()
// make channel proof
channelKey := host.KeyChannel(channelB.PortID, channelB.ID)
proof, proofHeight = suite.chainB.QueryProof(channelKey)
tc.malleate() // make changes as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
err := clientState.VerifyChannelState(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
channelB.PortID, channelB.ID, 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.
func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {
var (
clientState *types.ClientState
proof []byte
proofHeight uint64
prefix commitmenttypes.MerklePrefix
)
testCases := []struct {
name string
clientState *ibctmtypes.ClientState
commitment []byte
consensusState ibctmtypes.ConsensusState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
name string
malleate func()
expPass bool
}{
// FIXME: uncomment
// {
// name: "successful verification",
// clientState: ibctmtypes.NewClientState(chainID, height, commitmenttypes.GetSDKSpecs()),
// connection: conn,
// consensusState: ibctmtypes.ConsensusState{
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
// },
// prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
// expPass: true,
// },
{
name: "ApplyPrefix failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
commitment: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
"successful verification", func() {}, true,
},
{
name: "latest client height < height",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
commitment: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"ApplyPrefix failed", func() {
prefix = commitmenttypes.MerklePrefix{}
}, false,
},
{
name: "client is frozen",
clientState: &ibctmtypes.ClientState{LatestHeight: height, FrozenHeight: height - 1},
commitment: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"latest client height < height", func() {
proofHeight = clientState.LatestHeight + 1
}, false,
},
{
name: "proof verification failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
commitment: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
NextValidatorsHash: suite.valsHash,
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
"client is frozen", func() {
clientState.FrozenHeight = 1
}, false,
},
{
"proof verification failed", func() {
proof = invalidProof
}, false,
},
}
for i, tc := range testCases {
for _, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketCommitment(
nil, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.commitment, tc.consensusState,
)
suite.Run(tc.name, func() {
suite.SetupTest() // reset
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)
}
// setup testing conditions
clientA, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet := channeltypes.NewPacket(ibctesting.TestHash, 1, channelB.PortID, channelB.ID, channelA.PortID, channelA.ID, 100, 0)
err := suite.coordinator.SendPacket(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
var ok bool
clientStateI := suite.chainA.GetClientState(clientA)
clientState, ok = clientStateI.(*types.ClientState)
suite.Require().True(ok)
prefix = suite.chainB.GetPrefix()
// make packet commitment proof
packetKey := host.KeyPacketCommitment(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight = suite.chainB.QueryProof(packetKey)
tc.malleate() // make changes as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
err = clientState.VerifyPacketCommitment(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), channeltypes.CommitPacket(packet),
)
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.
func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
var (
clientState *types.ClientState
proof []byte
proofHeight uint64
prefix commitmenttypes.MerklePrefix
)
testCases := []struct {
name string
clientState *ibctmtypes.ClientState
ack []byte
consensusState ibctmtypes.ConsensusState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
name string
malleate func()
expPass bool
}{
// FIXME: uncomment
// {
// name: "successful verification",
// clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
// connection: conn,
// consensusState: ibctmtypes.ConsensusState{
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
// },
// prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
// expPass: true,
// },
{
name: "ApplyPrefix failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
ack: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
"successful verification", func() {}, true,
},
{
name: "latest client height < height",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
ack: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"ApplyPrefix failed", func() {
prefix = commitmenttypes.MerklePrefix{}
}, false,
},
{
name: "client is frozen",
clientState: &ibctmtypes.ClientState{LatestHeight: height, FrozenHeight: height - 1},
ack: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"latest client height < height", func() {
proofHeight = clientState.LatestHeight + 1
}, false,
},
{
name: "proof verification failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
ack: []byte{},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
NextValidatorsHash: suite.valsHash,
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
"client is frozen", func() {
clientState.FrozenHeight = 1
}, false,
},
{
"proof verification failed", func() {
proof = invalidProof
}, false,
},
}
for i, tc := range testCases {
for _, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgement(
nil, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.ack, tc.consensusState,
)
suite.Run(tc.name, func() {
suite.SetupTest() // reset
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)
}
// setup testing conditions
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet := channeltypes.NewPacket(ibctesting.TestHash, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, 100, 0)
// send packet
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// write ack
err = suite.coordinator.PacketExecuted(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
var ok bool
clientStateI := suite.chainA.GetClientState(clientA)
clientState, ok = clientStateI.(*types.ClientState)
suite.Require().True(ok)
prefix = suite.chainB.GetPrefix()
// make packet acknowledgement proof
acknowledgementKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight = suite.chainB.QueryProof(acknowledgementKey)
tc.malleate() // make changes as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
err = clientState.VerifyPacketAcknowledgement(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibctesting.TestHash,
)
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) TestVerifyPacketAcknowledgementAbsence() {
var (
clientState *types.ClientState
proof []byte
proofHeight uint64
prefix commitmenttypes.MerklePrefix
)
testCases := []struct {
name string
clientState *ibctmtypes.ClientState
consensusState ibctmtypes.ConsensusState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
name string
malleate func()
expPass bool
}{
// FIXME: uncomment
// {
// name: "successful verification",
// clientState: ibctmtypes.NewClientState(chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
// connection: conn,
// consensusState: ibctmtypes.ConsensusState{
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
// },
// prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
// expPass: true,
// },
{
name: "ApplyPrefix failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
"successful verification", func() {}, true,
},
{
name: "latest client height < height",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"ApplyPrefix failed", func() {
prefix = commitmenttypes.MerklePrefix{}
}, false,
},
{
name: "client is frozen",
clientState: &ibctmtypes.ClientState{LatestHeight: height, FrozenHeight: height - 1},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"latest client height < height", func() {
proofHeight = clientState.LatestHeight + 1
}, false,
},
{
name: "proof verification failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
NextValidatorsHash: suite.valsHash,
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
"client is frozen", func() {
clientState.FrozenHeight = 1
}, false,
},
{
"proof verification failed", func() {
proof = invalidProof
}, false,
},
}
for i, tc := range testCases {
for _, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgementAbsence(
nil, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.consensusState,
)
suite.Run(tc.name, func() {
suite.SetupTest() // reset
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)
}
// setup testing conditions
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet := channeltypes.NewPacket(ibctesting.TestHash, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, 100, 0)
// send packet, but no recv
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// need to update chainA's client representing chainB to prove missing ack
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
var ok bool
clientStateI := suite.chainA.GetClientState(clientA)
clientState, ok = clientStateI.(*types.ClientState)
suite.Require().True(ok)
prefix = suite.chainB.GetPrefix()
// make packet acknowledgement absence proof
acknowledgementKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight = suite.chainB.QueryProof(acknowledgementKey)
tc.malleate() // make changes as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
err = clientState.VerifyPacketAcknowledgementAbsence(
store, suite.chainA.Codec, proofHeight, &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.
func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
var (
clientState *types.ClientState
proof []byte
proofHeight uint64
prefix commitmenttypes.MerklePrefix
)
testCases := []struct {
name string
clientState *ibctmtypes.ClientState
consensusState ibctmtypes.ConsensusState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
name string
malleate func()
expPass bool
}{
// FIXME: uncomment
// {
// name: "successful verification",
// clientState: ibctmtypes.NewClientState(chainID, height, commitmenttypes.GetSDKSpecs()),
// connection: conn,
// consensusState: ibctmtypes.ConsensusState{
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
// },
// prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
// expPass: true,
// },
{
name: "ApplyPrefix failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
"successful verification", func() {}, true,
},
{
name: "latest client height < height",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"ApplyPrefix failed", func() {
prefix = commitmenttypes.MerklePrefix{}
}, false,
},
{
name: "client is frozen",
clientState: &ibctmtypes.ClientState{LatestHeight: height, FrozenHeight: height - 1},
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
"latest client height < height", func() {
proofHeight = clientState.LatestHeight + 1
}, false,
},
{
name: "proof verification failed",
clientState: ibctmtypes.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
consensusState: ibctmtypes.ConsensusState{
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
NextValidatorsHash: suite.valsHash,
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
"client is frozen", func() {
clientState.FrozenHeight = 1
}, false,
},
{
"proof verification failed", func() {
proof = invalidProof
}, false,
},
}
for i, tc := range testCases {
for _, tc := range testCases {
tc := tc
err := tc.clientState.VerifyNextSequenceRecv(
nil, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.consensusState,
)
suite.Run(tc.name, func() {
suite.SetupTest() // reset
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)
}
// setup testing conditions
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB)
packet := channeltypes.NewPacket(ibctesting.TestHash, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, 100, 0)
// send packet
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// write ack, next seq recv incremented
err = suite.coordinator.PacketExecuted(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
// need to update chainA's client representing chainB
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, clientexported.Tendermint)
var ok bool
clientStateI := suite.chainA.GetClientState(clientA)
clientState, ok = clientStateI.(*types.ClientState)
suite.Require().True(ok)
prefix = suite.chainB.GetPrefix()
// make next seq recv proof
nextSeqRecvKey := host.KeyNextSequenceRecv(packet.GetDestPort(), packet.GetDestChannel())
proof, proofHeight = suite.chainB.QueryProof(nextSeqRecvKey)
tc.malleate() // make changes as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
err = clientState.VerifyNextSequenceRecv(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(),
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -0,0 +1,37 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
// GetConsensusState retrieves the consensus state from the client prefixed
// store. An error is returned if the consensus state does not exist.
func GetConsensusState(store sdk.KVStore, cdc codec.BinaryMarshaler, height uint64) (*ConsensusState, error) {
bz := store.Get(host.KeyConsensusState(height))
if bz == nil {
return nil, sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"consensus state does not exist for height %d", height,
)
}
var consensusStateI clientexported.ConsensusState
if err := codec.UnmarshalAny(cdc, &consensusStateI, bz); err != nil {
return nil, err
}
consensusState, ok := consensusStateI.(*ConsensusState)
if !ok {
return nil, sdkerrors.Wrapf(
clienttypes.ErrInvalidConsensus,
"invalid consensus type %T, expected %T", consensusState, &ConsensusState{},
)
}
return consensusState, nil
}

View File

@ -0,0 +1,73 @@
package types_test
import (
"github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
func (suite *TendermintTestSuite) TestGetConsensusState() {
var (
height uint64
clientA string
)
testCases := []struct {
name string
malleate func()
expPass bool
}{
{
"success", func() {}, true,
},
{
"consensus state not found", func() {
// use height with no consensus state set
height = height + 1
}, false,
},
{
"not a consensus state interface", func() {
// marshal an empty client state and set as consensus state
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
clientStateBz := suite.chainA.App.IBCKeeper.ClientKeeper.MustMarshalClientState(&types.ClientState{})
store.Set(host.KeyConsensusState(height), clientStateBz)
}, false,
},
// TODO: uncomment upon merge of solomachine
// {
// "invalid consensus state (solomachine)", func() {
// // marshal and set solomachine consensus state
// store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
// consensusStateBz := suite.chainA.App.IBCKeeper.ClientKeeper.MustMarshalConsensusState(&solomachinetypes.ConsensusState{})
// store.Set(host.KeyConsensusState(height), consensusStateBz)
// }, false,
// },
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupTest()
clientA, _, _, _, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
clientState := suite.chainA.GetClientState(clientA)
height = clientState.GetLatestHeight()
tc.malleate() // change vars as necessary
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
consensusState, err := types.GetConsensusState(store, suite.chainA.Codec, height)
if tc.expPass {
suite.Require().NoError(err)
expConsensusState, found := suite.chainA.GetConsensusState(clientA, height)
suite.Require().True(found)
suite.Require().Equal(expConsensusState, consensusState)
} else {
suite.Require().Error(err)
suite.Require().Nil(consensusState)
}
})
}
}

View File

@ -14,6 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
const (
@ -28,6 +29,13 @@ const (
type TendermintTestSuite struct {
suite.Suite
coordinator *ibctesting.Coordinator
// testing chains used for convenience and readability
chainA *ibctesting.TestChain
chainB *ibctesting.TestChain
// TODO: deprecate usage in favor of testing package
ctx sdk.Context
aminoCdc *codec.LegacyAmino
cdc codec.Marshaler
@ -39,6 +47,11 @@ type TendermintTestSuite struct {
}
func (suite *TendermintTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
// TODO: deprecate usage in favor of testing package
checkTx := false
app := simapp.Setup(checkTx)

View File

@ -91,7 +91,6 @@ func (cs ClientState) VerifyConnectionState(
_ []byte,
connectionID string,
connectionEnd connectionexported.ConnectionI,
_ clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, host.ConnectionPath(connectionID))
if err != nil {
@ -130,7 +129,6 @@ func (cs ClientState) VerifyChannelState(
portID,
channelID string,
channel channelexported.ChannelI,
_ clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, host.ChannelPath(portID, channelID))
if err != nil {
@ -170,7 +168,6 @@ func (cs ClientState) VerifyPacketCommitment(
channelID string,
sequence uint64,
commitmentBytes []byte,
_ clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, host.PacketCommitmentPath(portID, channelID, sequence))
if err != nil {
@ -204,7 +201,6 @@ func (cs ClientState) VerifyPacketAcknowledgement(
channelID string,
sequence uint64,
acknowledgement []byte,
_ clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, host.PacketAcknowledgementPath(portID, channelID, sequence))
if err != nil {
@ -238,7 +234,6 @@ func (cs ClientState) VerifyPacketAcknowledgementAbsence(
portID,
channelID string,
sequence uint64,
_ clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, host.PacketAcknowledgementPath(portID, channelID, sequence))
if err != nil {
@ -264,7 +259,6 @@ func (cs ClientState) VerifyNextSequenceRecv(
portID,
channelID string,
nextSequenceRecv uint64,
_ clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, host.NextSequenceRecvPath(portID, channelID))
if err != nil {

View File

@ -88,7 +88,7 @@ func (suite *LocalhostTestSuite) TestVerifyConnectionState() {
tc := tc
err := tc.clientState.VerifyConnectionState(
suite.store, suite.cdc, height, tc.prefix, tc.proof, testConnectionID, &tc.connection, nil,
suite.store, suite.cdc, height, tc.prefix, tc.proof, testConnectionID, &tc.connection,
)
if tc.expPass {
@ -139,7 +139,7 @@ func (suite *LocalhostTestSuite) TestVerifyChannelState() {
tc := tc
err := tc.clientState.VerifyChannelState(
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, &tc.channel, nil,
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, &tc.channel,
)
if tc.expPass {
@ -194,7 +194,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketCommitment() {
tc := tc
err := tc.clientState.VerifyPacketCommitment(
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.commitment, nil,
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.commitment,
)
if tc.expPass {
@ -249,7 +249,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgement() {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgement(
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.ack, nil,
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.ack,
)
if tc.expPass {
@ -280,7 +280,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgementAbsence() {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgementAbsence(
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, nil,
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence,
)
if tc.expPass {
@ -330,7 +330,7 @@ func (suite *LocalhostTestSuite) TestVerifyNextSeqRecv() {
tc := tc
err := tc.clientState.VerifyNextSequenceRecv(
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, nil,
suite.store, suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence,
)
if tc.expPass {

View File

@ -15,6 +15,7 @@ import (
"github.com/tendermint/tendermint/version"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@ -70,6 +71,7 @@ type TestChain struct {
CurrentHeader abci.Header // header for current block height
QueryServer types.QueryServer
TxConfig client.TxConfig
Codec codec.BinaryMarshaler
Vals *tmtypes.ValidatorSet
Signers []tmtypes.PrivValidator
@ -127,6 +129,7 @@ func NewTestChain(t *testing.T, chainID string) *TestChain {
CurrentHeader: header,
QueryServer: app.IBCKeeper,
TxConfig: txConfig,
Codec: app.AppCodec(),
Vals: valSet,
Signers: signers,
senderPrivKey: senderPrivKey,