diff --git a/simapp/app.go b/simapp/app.go index 910ab9d753d0..5b600f8525d6 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -259,7 +259,7 @@ func NewSimApp( // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. - app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName) + app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName, staking.ModuleName) app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName) // NOTE: The genutils moodule must occur after staking so that pools are diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 996a5343c797..aeb861db3de8 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -24,7 +24,10 @@ type ClientState interface { VerifyClientConsensusState( cdc *codec.Codec, + root commitmentexported.Root, height uint64, + counterpartyClientIdentifier string, + consensusHeight uint64, prefix commitmentexported.Prefix, proof commitmentexported.Proof, consensusState ConsensusState, diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index ef5ab61bf87f..160bcde630fa 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -135,8 +135,9 @@ func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height uint64) (exported. valSet := stakingtypes.Validators(histInfo.Valset) consensusState := ibctmtypes.ConsensusState{ - Height: height, - Timestamp: ctx.BlockTime(), + Height: height, + // FIXME: Currently commented out due to time normalisation issues. + //Timestamp: histInfo.Header.Time, Root: commitmenttypes.NewMerkleRoot(histInfo.Header.AppHash), ValidatorSet: tmtypes.NewValidatorSet(valSet.ToTmValidators()), } diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 5b8592f83daa..e7cc6b796dfe 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -88,7 +88,7 @@ func (k Keeper) ConnOpenTry( // Check that ChainA stored the correct ConsensusState of chainB at the given consensusHeight if err := k.VerifyClientConsensusState( - ctx, connection, consensusHeight, proofConsensus, expectedConsensusState, + ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState, ); err != nil { return err } @@ -177,7 +177,7 @@ func (k Keeper) ConnOpenAck( // Ensure that ChainB has stored the correct ConsensusState for chainA at the consensusHeight if err := k.VerifyClientConsensusState( - ctx, connection, consensusHeight, proofConsensus, expectedConsensusState, + ctx, connection, proofHeight, consensusHeight, proofConsensus, expectedConsensusState, ); err != nil { return err } diff --git a/x/ibc/03-connection/keeper/handshake_test.go b/x/ibc/03-connection/keeper/handshake_test.go index 83a2ae0958ef..0df27a306ef2 100644 --- a/x/ibc/03-connection/keeper/handshake_test.go +++ b/x/ibc/03-connection/keeper/handshake_test.go @@ -5,7 +5,6 @@ import ( connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -47,66 +46,62 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { // TestConnOpenTry - Chain B (ID #2) calls ConnOpenTry to verify the state of // connection on Chain A (ID #1) is INIT func (suite *KeeperTestSuite) TestConnOpenTry() { + // counterparty for A on B counterparty := connection.NewCounterparty( testClientIDB, testConnectionIDA, suite.chainB.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), ) - var ( - consensusHeight int64 = 0 - proofHeight int64 = 0 - ) testCases := []struct { - msg string - proofInit commitmentexported.Proof - proofConsensus commitmentexported.Proof - malleate func() - expPass bool + msg string + malleate func() uint64 + expPass bool }{ - {"success", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"success", func() uint64 { suite.chainB.CreateClient(suite.chainA) - suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) - proofHeight = suite.chainA.Header.Height suite.chainA.CreateClient(suite.chainB) - consensusHeight = suite.chainB.Header.Height + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) suite.chainB.updateClient(suite.chainA) suite.chainA.updateClient(suite.chainB) + return uint64(suite.chainB.Header.Height - 1) }, true}, - {"consensus height > latest height", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - consensusHeight = 100 + {"consensus height > latest height", func() uint64 { + return 0 + }, false}, + {"self consensus state not found", func() uint64 { + //suite.ctx = suite.ctx.WithBlockHeight(100) + return 100 }, false}, - // {"self consensus state not found", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - // consensusHeight = 100 - // suite.ctx = suite.ctx.WithBlockHeight(100) - // }, false}, - {"connection state verification invalid", ibctypes.InvalidProof{}, ibctypes.ValidProof{}, func() { + {"connection state verification invalid", func() uint64 { suite.chainB.CreateClient(suite.chainA) suite.chainA.CreateClient(suite.chainB) - consensusHeight = suite.chainB.Header.Height suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.UNINITIALIZED) suite.chainB.updateClient(suite.chainA) + return 0 }, false}, - {"consensus state verification invalid", ibctypes.ValidProof{}, ibctypes.InvalidProof{}, func() { + {"consensus state verification invalid", func() uint64 { suite.chainB.CreateClient(suite.chainA) suite.chainA.CreateClient(suite.chainB) - consensusHeight = suite.chainB.Header.Height suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) suite.chainB.updateClient(suite.chainA) suite.chainA.updateClient(suite.chainB) + return uint64(suite.chainB.Header.Height) }, false}, - {"invalid previous connection", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"invalid previous connection", func() uint64 { suite.chainB.CreateClient(suite.chainA) suite.chainA.CreateClient(suite.chainB) - consensusHeight = suite.chainB.Header.Height suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) suite.chainB.updateClient(suite.chainA) suite.chainA.updateClient(suite.chainB) + return 0 }, false}, - {"couldn't add connection to client", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"couldn't add connection to client", func() uint64 { suite.chainB.CreateClient(suite.chainA) - consensusHeight = suite.chainB.Header.Height suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.UNINITIALIZED) suite.chainB.updateClient(suite.chainA) suite.chainA.updateClient(suite.chainB) + return 0 }, false}, } @@ -115,24 +110,24 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - tc.malleate() + consensusHeight := tc.malleate() - // connectionKey := ibctypes.KeyConnection(testConnectionIDA) - // proofInit, proofHeight := suite.queryProof(connectionKey) + connectionKey := ibctypes.KeyConnection(testConnectionIDA) + proofInit, proofHeight := queryProof(suite.chainA, connectionKey) - // consensusKey := ibctypes.KeyConsensusState(testClientIDA, uint64(proofHeight)) - // proofConsensus, consensusHeight := suite.queryProof(consensusKey) + consensusKey := ibctypes.KeyConsensusState(testClientIDB, consensusHeight) + proofConsensus, _ := queryProof(suite.chainA, consensusKey) err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenTry( suite.chainB.GetContext(), testConnectionIDB, counterparty, testClientIDA, - connection.GetCompatibleVersions(), tc.proofInit, tc.proofConsensus, - uint64(proofHeight), uint64(consensusHeight), + connection.GetCompatibleVersions(), proofInit, proofConsensus, + uint64(proofHeight+1), consensusHeight, ) if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + suite.Require().NoError(err, "valid test case %d failed with consensus height %d and proof height %d: %s", i, consensusHeight, proofHeight, tc.msg) } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + suite.Require().Error(err, "invalid test case %d passed with consensus height %d and proof height %d: %s", i, consensusHeight, proofHeight, tc.msg) } }) } @@ -143,66 +138,60 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { func (suite *KeeperTestSuite) TestConnOpenAck() { version := connection.GetCompatibleVersions()[0] - var ( - consensusHeight int64 = 0 - proofHeight int64 = 0 - ) - testCases := []struct { - msg string - version string - proofTry commitmentexported.Proof - proofConsensus commitmentexported.Proof - malleate func() - expPass bool + msg string + version string + malleate func() uint64 + expPass bool }{ - {"success", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"success", version, func() uint64 { suite.chainA.CreateClient(suite.chainB) suite.chainB.CreateClient(suite.chainA) suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) - consensusHeight = suite.chainB.Header.Height - proofHeight = suite.chainA.Header.Height suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) suite.chainB.updateClient(suite.chainA) suite.chainA.updateClient(suite.chainB) + return uint64(suite.chainB.Header.Height) }, true}, - {"consensus height > latest height", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - consensusHeight = 100 + {"consensus height > latest height", version, func() uint64 { + return 10 }, false}, - {"connection not found", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - consensusHeight = suite.chainB.Header.Height + {"connection not found", version, func() uint64 { + return 2 }, false}, - {"connection state is not INIT", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"connection state is not INIT", version, func() uint64 { suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.UNINITIALIZED) suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) }, false}, - {"incompatible IBC versions", "2.0", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"incompatible IBC versions", "2.0", func() uint64 { suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) }, false}, - {"self consensus state not found", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + {"self consensus state not found", version, func() uint64 { suite.chainB.CreateClient(suite.chainA) suite.chainA.CreateClient(suite.chainB) suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) suite.chainB.updateClient(suite.chainA) - consensusHeight = 100 + return uint64(suite.chainB.Header.Height) }, false}, - {"connection state verification failed", version, ibctypes.InvalidProof{}, ibctypes.ValidProof{}, func() { + {"connection state verification failed", version, func() uint64 { suite.chainB.CreateClient(suite.chainA) - consensusHeight = suite.chainB.Header.Height suite.chainA.CreateClient(suite.chainB) suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) }, false}, - {"consensus state verification failed", version, ibctypes.ValidProof{}, ibctypes.InvalidProof{}, func() { + {"consensus state verification failed", version, func() uint64 { suite.chainB.CreateClient(suite.chainA) - consensusHeight = suite.chainB.Header.Height suite.chainA.CreateClient(suite.chainB) suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) suite.chainB.updateClient(suite.chainA) + return uint64(suite.chainB.Header.Height) }, false}, } @@ -211,40 +200,35 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - tc.malleate() + consensusHeight := tc.malleate() - // connectionKey := ibctypes.KeyConnection(testConnectionIDB) - // proofTry, proofHeight := suite.queryProof(connectionKey) + connectionKey := ibctypes.KeyConnection(testConnectionIDB) + proofTry, proofHeight := queryProof(suite.chainB, connectionKey) - // consensusKey := ibctypes.KeyConsensusState(testClientIDB, uint64(proofHeight)) - // proofConsensus, consensusHeight := suite.queryProof(consensusKey) + consensusKey := ibctypes.KeyConsensusState(testClientIDA, uint64(consensusHeight)) + proofConsensus, _ := queryProof(suite.chainB, consensusKey) err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenAck( - suite.chainA.GetContext(), testConnectionIDA, tc.version, tc.proofTry, tc.proofConsensus, - uint64(proofHeight), uint64(consensusHeight), + suite.chainA.GetContext(), testConnectionIDA, tc.version, proofTry, proofConsensus, + uint64(proofHeight+1), consensusHeight, ) if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + suite.Require().NoError(err, "valid test case %d failed with consensus height %d: %s", i, consensusHeight, tc.msg) } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + suite.Require().Error(err, "invalid test case %d passed with consensus height %d: %s", i, consensusHeight, tc.msg) } }) } } -// TestConnOpenAck - Chain B (ID #2) calls ConnOpenConfirm to confirm that +// TestConnOpenConfirm - Chain B (ID #2) calls ConnOpenConfirm to confirm that // Chain A (ID #1) state is now OPEN. func (suite *KeeperTestSuite) TestConnOpenConfirm() { - // consensusHeight := int64(0) - proofHeight := int64(0) - testCases := []testCase{ {"success", func() { suite.chainB.CreateClient(suite.chainA) suite.chainA.CreateClient(suite.chainB) - proofHeight = suite.chainB.Header.Height - // consensusHeight = suite.chainA.Header.Height suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN) suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) suite.chainB.updateClient(suite.chainA) @@ -252,19 +236,15 @@ func (suite *KeeperTestSuite) TestConnOpenConfirm() { {"connection not found", func() {}, false}, {"chain B's connection state is not TRYOPEN", func() { suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) - }, false}, - {"consensus state not found", func() { - suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.OPEN) suite.chainA.updateClient(suite.chainB) }, false}, {"connection state verification failed", func() { suite.chainB.CreateClient(suite.chainA) suite.chainA.CreateClient(suite.chainB) - // consensusHeight = suite.chainA.Header.Height - proofHeight = suite.chainB.Header.Height suite.chainB.updateClient(suite.chainA) - suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) - suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.TRYOPEN) suite.chainA.updateClient(suite.chainA) }, false}, } @@ -276,17 +256,17 @@ func (suite *KeeperTestSuite) TestConnOpenConfirm() { tc.malleate() - // connectionKey := ibctypes.KeyConnection(testConnectionIDB) - // proofAck, proofHeight := suite.queryProof(connectionKey) + connectionKey := ibctypes.KeyConnection(testConnectionIDA) + proofAck, proofHeight := queryProof(suite.chainA, connectionKey) if tc.expPass { err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( - suite.chainB.GetContext(), testConnectionIDB, ibctypes.ValidProof{}, uint64(proofHeight), + suite.chainB.GetContext(), testConnectionIDB, proofAck, uint64(proofHeight+1), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( - suite.chainB.GetContext(), testConnectionIDB, ibctypes.InvalidProof{}, uint64(proofHeight), + suite.chainB.GetContext(), testConnectionIDB, proofAck, uint64(proofHeight+1), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } diff --git a/x/ibc/03-connection/keeper/keeper_test.go b/x/ibc/03-connection/keeper/keeper_test.go index 2ed104744b71..423cd588bd18 100644 --- a/x/ibc/03-connection/keeper/keeper_test.go +++ b/x/ibc/03-connection/keeper/keeper_test.go @@ -61,10 +61,10 @@ func (suite *KeeperTestSuite) SetupTest() { } // nolint: unused -func (suite *KeeperTestSuite) queryProof(key []byte) (commitmenttypes.MerkleProof, int64) { - res := suite.chainA.App.Query(abci.RequestQuery{ +func queryProof(chain *TestChain, key []byte) (commitmenttypes.MerkleProof, uint64) { + res := chain.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", storeKey), - Height: suite.chainA.App.LastBlockHeight(), + Height: chain.App.LastBlockHeight(), Data: key, Prove: true, }) @@ -73,7 +73,7 @@ func (suite *KeeperTestSuite) queryProof(key []byte) (commitmenttypes.MerkleProo Proof: res.Proof, } - return proof, res.Height + return proof, uint64(res.Height) } func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) @@ -122,6 +122,9 @@ func (suite KeeperTestSuite) TestGetAllConnections() { suite.Require().ElementsMatch(expConnections, connections) } +// TestChain is a testing struct that wraps a simapp with the latest Header, Vals and Signers +// It also contains a field called ClientID. This is the clientID that *other* chains use +// to refer to this TestChain. For simplicity's sake it is also the chainID on the TestChain Header type TestChain struct { ClientID string App *simapp.SimApp @@ -135,7 +138,7 @@ func NewTestChain(clientID string) *TestChain { validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) signers := []tmtypes.PrivValidator{privVal} - now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + now := time.Now() header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, valSet, signers) @@ -171,12 +174,18 @@ func (chain *TestChain) CreateClient(client *TestChain) error { validators := []staking.Validator{validator} histInfo := staking.HistoricalInfo{ Header: abci.Header{ + Time: client.Header.Time, AppHash: commitID.Hash, }, Valset: validators, } client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + // also set staking params + stakingParams := staking.DefaultParams() + stakingParams.HistoricalEntries = 10 + client.App.StakingKeeper.SetParams(ctxClient, stakingParams) + // Create target ctx ctxTarget := chain.GetContext() @@ -218,8 +227,15 @@ func (chain *TestChain) updateClient(client *TestChain) { // always commit when updateClient and begin a new block client.App.Commit() commitID := client.App.LastCommitID() - client.Header = nextHeader(client) + + /* + err := chain.App.IBCKeeper.ClientKeeper.UpdateClient(ctxTarget, client.ClientID, client.Header) + if err != nil { + panic(err) + } + */ + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) // Set HistoricalInfo on client chain after Commit @@ -232,6 +248,7 @@ func (chain *TestChain) updateClient(client *TestChain) { validators := []staking.Validator{validator} histInfo := staking.HistoricalInfo{ Header: abci.Header{ + Time: client.Header.Time, AppHash: commitID.Hash, }, Valset: validators, @@ -239,8 +256,9 @@ func (chain *TestChain) updateClient(client *TestChain) { client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) consensusState := ibctmtypes.ConsensusState{ - Height: uint64(client.Header.Height), - Timestamp: client.Header.Time, + Height: uint64(client.Header.Height), + // FIXME: currently commented out due to time normalisation issues. + //Timestamp: client.Header.Time, Root: commitmenttypes.NewMerkleRoot(commitID.Hash), ValidatorSet: client.Vals, } @@ -296,5 +314,5 @@ func (chain *TestChain) createChannel( func nextHeader(chain *TestChain) ibctmtypes.Header { return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, - chain.Header.Time.Add(time.Minute), chain.Vals, chain.Vals, chain.Signers) + time.Now(), chain.Vals, chain.Vals, chain.Signers) } diff --git a/x/ibc/03-connection/keeper/verify.go b/x/ibc/03-connection/keeper/verify.go index aea829d922d5..4524444fe07b 100644 --- a/x/ibc/03-connection/keeper/verify.go +++ b/x/ibc/03-connection/keeper/verify.go @@ -16,6 +16,7 @@ func (k Keeper) VerifyClientConsensusState( ctx sdk.Context, connection exported.ConnectionI, height uint64, + consensusHeight uint64, proof commitmentexported.Proof, consensusState clientexported.ConsensusState, ) error { @@ -25,8 +26,13 @@ func (k Keeper) VerifyClientConsensusState( return sdkerrors.Wrap(clienttypes.ErrClientNotFound, clientID) } + targetConsState, found := k.clientKeeper.GetClientConsensusState(ctx, clientID, height) + if !found { + return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "clientID: %s with height: %d", clientID, height) + } + return clientState.VerifyClientConsensusState( - k.cdc, height, connection.GetCounterparty().GetPrefix(), proof, consensusState, + k.cdc, targetConsState.GetRoot(), height, connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState, ) } diff --git a/x/ibc/03-connection/keeper/verify_test.go b/x/ibc/03-connection/keeper/verify_test.go index 39a817a13d49..bd48000da1c3 100644 --- a/x/ibc/03-connection/keeper/verify_test.go +++ b/x/ibc/03-connection/keeper/verify_test.go @@ -3,10 +3,10 @@ package keeper_test import ( "fmt" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -20,11 +20,11 @@ const ( ) func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { + // create connection on chainA to chainB counterparty := types.NewCounterparty( testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), ) - connection1 := types.NewConnectionEnd( exported.UNINITIALIZED, testClientIDB, counterparty, types.GetCompatibleVersions(), @@ -33,16 +33,21 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { cases := []struct { msg string connection types.ConnectionEnd - proof commitmentexported.Proof - malleate func() + malleate func() clientexported.ConsensusState expPass bool }{ - {"verification success", connection1, ibctypes.ValidProof{}, func() { + {"verification success", connection1, func() clientexported.ConsensusState { suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + consState := suite.chainA.Header.ConsensusState() + return consState }, true}, - {"client state not found", connection1, ibctypes.ValidProof{}, func() {}, false}, - {"verification failed", connection1, ibctypes.InvalidProof{}, func() { + {"client state not found", connection1, func() clientexported.ConsensusState { + return suite.chainB.Header.ConsensusState() + }, false}, + {"verification failed", connection1, func() clientexported.ConsensusState { suite.chainA.CreateClient(suite.chainA) + return suite.chainA.Header.ConsensusState() }, false}, } @@ -53,15 +58,21 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - tc.malleate() - proofHeight := uint64(suite.chainB.Header.Height) + consState := tc.malleate() + + // perform a couple updates of chain B on chain A + suite.chainA.updateClient(suite.chainB) + suite.chainA.updateClient(suite.chainB) - // TODO: remove mocked types and uncomment - // consensusKey := ibctypes.KeyConsensusState(testClientIDA, uint64(suite.app.LastBlockHeight())) - // proof, proofHeight := suite.queryProof(consensusKey) + // TODO: is this the right consensus height + consensusHeight := uint64(suite.chainA.Header.Height) + consensusKey := ibctypes.KeyConsensusState(testClientIDA, consensusHeight) + + // get proof that chainB stored chainA' consensus state + proof, proofHeight := queryProof(suite.chainB, consensusKey) err := suite.chainA.App.IBCKeeper.ConnectionKeeper.VerifyClientConsensusState( - suite.chainA.GetContext(), tc.connection, proofHeight, tc.proof, suite.chainB.Header.ConsensusState(), + suite.chainA.GetContext(), tc.connection, proofHeight+1, consensusHeight, proof, consState, ) if tc.expPass { @@ -74,21 +85,23 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { } func (suite *KeeperTestSuite) TestVerifyConnectionState() { - // connectionKey := ibctypes.KeyConnection(testConnectionIDA) + connectionKey := ibctypes.KeyConnection(testConnectionIDA) + var invalidProofHeight uint64 cases := []struct { msg string - proof commitmentexported.Proof malleate func() expPass bool }{ - {"verification success", ibctypes.ValidProof{}, func() { + {"verification success", func() { suite.chainA.CreateClient(suite.chainB) suite.chainB.CreateClient(suite.chainA) + invalidProofHeight = 0 // don't use this }, true}, - {"client state not found", ibctypes.ValidProof{}, func() {}, false}, - {"verification failed", ibctypes.InvalidProof{}, func() { + {"client state not found", func() {}, false}, + {"verification failed", func() { suite.chainA.CreateClient(suite.chainB) suite.chainB.CreateClient(suite.chainA) + invalidProofHeight = 10 // make proofHeight incorrect }, false}, } @@ -106,19 +119,24 @@ func (suite *KeeperTestSuite) TestVerifyConnectionState() { expectedConnection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN) // // create expected connection + // TODO: why is this commented // expectedConnection := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, []string{"1.0.0"}) // perform a couple updates of chain A on chain B suite.chainB.updateClient(suite.chainA) suite.chainB.updateClient(suite.chainA) - proofHeight := uint64(suite.chainA.Header.Height) - // proof, proofHeight := suite.queryProof(connectionKey) + proof, proofHeight := queryProof(suite.chainA, connectionKey) + // if invalidProofHeight has been set, use that value instead + if invalidProofHeight != 0 { + proofHeight = invalidProofHeight + } + // Create B's connection to A counterparty := types.NewCounterparty(testClientIDB, testConnectionIDA, commitmenttypes.NewMerklePrefix([]byte("ibc"))) connection := types.NewConnectionEnd(exported.UNINITIALIZED, testClientIDA, counterparty, []string{"1.0.0"}) // Ensure chain B can verify connection exists in chain A err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyConnectionState( - suite.chainB.GetContext(), connection, proofHeight, tc.proof, testConnectionIDA, expectedConnection, + suite.chainB.GetContext(), connection, proofHeight+1, proof, testConnectionIDA, expectedConnection, ) if tc.expPass { @@ -131,22 +149,33 @@ func (suite *KeeperTestSuite) TestVerifyConnectionState() { } func (suite *KeeperTestSuite) TestVerifyChannelState() { - // channelKey := ibctypes.KeyChannel(testPort1, testChannel1) + channelKey := ibctypes.KeyChannel(testPort1, testChannel1) + + // create connection of chainB to pass into verify function + counterparty := types.NewCounterparty( + testClientIDB, testConnectionIDB, + suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + ) + + connection := types.NewConnectionEnd( + exported.UNINITIALIZED, testClientIDA, counterparty, + types.GetCompatibleVersions(), + ) + cases := []struct { msg string - proof commitmentexported.Proof proofHeight uint64 malleate func() expPass bool }{ - {"verification success", ibctypes.ValidProof{}, 2, func() { + {"verification success", 0, func() { suite.chainB.CreateClient(suite.chainA) }, true}, - {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, - {"consensus state not found", ibctypes.ValidProof{}, 100, func() { + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { suite.chainB.CreateClient(suite.chainA) }, false}, - {"verification failed", ibctypes.InvalidProof{}, 2, func() { + {"verification failed", 7, func() { suite.chainB.CreateClient(suite.chainB) }, false}, } @@ -160,7 +189,6 @@ func (suite *KeeperTestSuite) TestVerifyChannelState() { tc.malleate() // Create and store channel on chain A - connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) channel := suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnectionIDA, @@ -170,9 +198,14 @@ func (suite *KeeperTestSuite) TestVerifyChannelState() { suite.chainB.updateClient(suite.chainA) // Check that Chain B can verify channel is stored on chainA - // proof, proofHeight := suite.queryProof(channelKey) + proof, proofHeight := queryProof(suite.chainA, channelKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyChannelState( - suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, testChannel1, channel, ) @@ -186,24 +219,20 @@ func (suite *KeeperTestSuite) TestVerifyChannelState() { } func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { - // commitmentKey := ibctypes.KeyPacketCommitment(testPort1, testChannel1, 1) + commitmentKey := ibctypes.KeyPacketCommitment(testPort1, testChannel1, 1) commitmentBz := []byte("commitment") cases := []struct { msg string - proof commitmentexported.Proof proofHeight uint64 malleate func() expPass bool }{ - {"verification success", ibctypes.ValidProof{}, 2, func() { + {"verification success", 0, func() { suite.chainB.CreateClient(suite.chainA) }, true}, - {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, - {"consensus state not found", ibctypes.ValidProof{}, 100, func() { - suite.chainB.CreateClient(suite.chainA) - }, false}, - {"verification failed", ibctypes.InvalidProof{}, 2, func() { + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { suite.chainB.CreateClient(suite.chainA) }, false}, } @@ -225,9 +254,14 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { suite.chainB.updateClient(suite.chainA) // Check that ChainB can verify PacketCommitment stored in chainA - // proof, proofHeight := suite.queryProof(commitmentKey) + proof, proofHeight := queryProof(suite.chainA, commitmentKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketCommitment( - suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, testChannel1, 1, commitmentBz, ) @@ -241,26 +275,22 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { } func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { - // packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1) + packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1) ack := []byte("acknowledgement") cases := []struct { msg string - proof commitmentexported.Proof proofHeight uint64 malleate func() expPass bool }{ - {"verification success", ibctypes.ValidProof{}, 2, func() { + {"verification success", 0, func() { suite.chainB.CreateClient(suite.chainA) }, true}, - {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, - {"consensus state not found", ibctypes.ValidProof{}, 100, func() { + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { suite.chainB.CreateClient(suite.chainA) }, false}, - {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.chainB.CreateClient(suite.chainB) - }, false}, } for i, tc := range cases { @@ -272,10 +302,16 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort1, testChannel1, 1, ack) suite.chainB.updateClient(suite.chainA) - // proof, proofHeight := suite.queryProof(packetAckKey) + + // TODO check this proof height + proof, proofHeight := queryProof(suite.chainA, packetAckKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgement( - suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, testChannel1, 1, ack, ) @@ -289,25 +325,21 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { } func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() { - // packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1) + packetAckKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 1) cases := []struct { msg string - proof commitmentexported.Proof proofHeight uint64 malleate func() expPass bool }{ - {"verification success", ibctypes.ValidProof{}, 2, func() { + {"verification success", 0, func() { suite.chainB.CreateClient(suite.chainA) }, true}, - {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, - {"consensus state not found", ibctypes.ValidProof{}, 100, func() { + {"client state not found", 0, func() {}, false}, + {"consensus state not found", 100, func() { suite.chainB.CreateClient(suite.chainA) }, false}, - {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.chainB.CreateClient(suite.chainB) - }, false}, } for i, tc := range cases { @@ -319,10 +351,14 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() { connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) suite.chainB.updateClient(suite.chainA) - // proof, proofHeight := suite.queryProof(packetAckKey) + proof, proofHeight := queryProof(suite.chainA, packetAckKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgementAbsence( - suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, testChannel1, 1, ) @@ -336,25 +372,21 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() { } func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { - // nextSeqRcvKey := ibctypes.KeyNextSequenceRecv(testPort1, testChannel1) + nextSeqRcvKey := ibctypes.KeyNextSequenceRecv(testPort1, testChannel1) cases := []struct { msg string - proof commitmentexported.Proof proofHeight uint64 malleate func() expPass bool }{ - {"verification success", ibctypes.ValidProof{}, 2, func() { + {"verification success", uint64(0), func() { suite.chainB.CreateClient(suite.chainA) }, true}, - {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, - {"consensus state not found", ibctypes.ValidProof{}, 100, func() { + {"client state not found", uint64(0), func() {}, false}, + {"consensus state not found", uint64(100), func() { suite.chainB.CreateClient(suite.chainA) }, false}, - {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.chainB.CreateClient(suite.chainB) - }, false}, } for i, tc := range cases { @@ -367,9 +399,14 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort1, testChannel1, 1) suite.chainB.updateClient(suite.chainA) - // proof, proofHeight := suite.queryProof(nextSeqRcvKey) + proof, proofHeight := queryProof(suite.chainA, nextSeqRcvKey) + // if testcase proofHeight is not 0, replace proofHeight with this value + if tc.proofHeight != 0 { + proofHeight = tc.proofHeight + } + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyNextSequenceRecv( - suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, + suite.chainB.GetContext(), connection, proofHeight+1, proof, testPort1, testChannel1, 1, ) diff --git a/x/ibc/04-channel/keeper/handshake_test.go b/x/ibc/04-channel/keeper/handshake_test.go index 2b5257b8e61b..7cc6f9eba755 100644 --- a/x/ibc/04-channel/keeper/handshake_test.go +++ b/x/ibc/04-channel/keeper/handshake_test.go @@ -6,6 +6,7 @@ import ( connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) func (suite *KeeperTestSuite) TestChanOpenInit() { @@ -54,14 +55,19 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { func (suite *KeeperTestSuite) TestChanOpenTry() { counterparty := types.NewCounterparty(testPort1, testChannel1) + channelKey := ibctypes.KeyChannel(testPort1, testChannel1) testCases := []testCase{ {"success", func() { suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) _ = suite.chainA.createConnection( testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) + suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.INIT, exported.ORDERED, testConnectionIDA) }, true}, {"previous channel with invalid state", func() { _ = suite.chainA.createChannel( @@ -97,13 +103,15 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { tc.malleate() - proofHeight := suite.chainB.Header.Height + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainB, channelKey) if tc.expPass { err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenTry( suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDB}, testPort2, testChannel2, counterparty, testChannelVersion, testChannelVersion, - validProof{}, uint64(proofHeight), + proof, proofHeight+1, ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { @@ -119,15 +127,26 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { } func (suite *KeeperTestSuite) TestChanOpenAck() { + channelKey := ibctypes.KeyChannel(testPort2, testChannel2) + testCases := []testCase{ {"success", func() { + suite.chainA.CreateClient(suite.chainB) suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) _ = suite.chainB.createConnection( testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.chainB.createChannel( - testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, + _ = suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.INIT, + exported.ORDERED, testConnectionIDB, + ) + suite.chainB.createChannel( + testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, exported.ORDERED, testConnectionIDA, ) }, true}, @@ -183,17 +202,20 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { tc.malleate() - proofHeight := suite.chainA.Header.Height + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainB, channelKey) + if tc.expPass { - err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenAck( - suite.chainB.GetContext(), testPort1, testChannel1, testChannelVersion, - validProof{}, uint64(proofHeight), + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenAck( + suite.chainA.GetContext(), testPort1, testChannel1, testChannelVersion, + proof, proofHeight+1, ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenAck( - suite.chainB.GetContext(), testPort1, testChannel1, testChannelVersion, - invalidProof{}, uint64(proofHeight), + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenAck( + suite.chainA.GetContext(), testPort1, testChannel1, testChannelVersion, + invalidProof{}, proofHeight+1, ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -202,17 +224,26 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { } func (suite *KeeperTestSuite) TestChanOpenConfirm() { + channelKey := ibctypes.KeyChannel(testPort2, testChannel2) + testCases := []testCase{ {"success", func() { suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) _ = suite.chainA.createConnection( testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, + connectionexported.TRYOPEN, + ) + suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN, ) _ = suite.chainA.createChannel( - testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, + testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDB, ) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, + exported.TRYOPEN, exported.ORDERED, testConnectionIDA) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is not TRYOPEN", func() { @@ -266,17 +297,20 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { tc.malleate() - proofHeight := suite.chainB.Header.Height + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, channelKey) + if tc.expPass { - err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( - suite.chainA.GetContext(), testPort2, testChannel2, - validProof{}, uint64(proofHeight), + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( + suite.chainB.GetContext(), testPort1, testChannel1, + proof, proofHeight+1, ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( - suite.chainA.GetContext(), testPort2, testChannel2, - invalidProof{}, uint64(proofHeight), + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( + suite.chainB.GetContext(), testPort1, testChannel1, + invalidProof{}, proofHeight+1, ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -341,17 +375,28 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { } func (suite *KeeperTestSuite) TestChanCloseConfirm() { + channelKey := ibctypes.KeyChannel(testPort1, testChannel1) + testCases := []testCase{ {"success", func() { + suite.chainA.CreateClient(suite.chainB) suite.chainB.CreateClient(suite.chainA) _ = suite.chainB.createConnection( testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, connectionexported.OPEN, ) + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, + connectionexported.OPEN, + ) _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDB, ) + suite.chainA.createChannel( + testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, + exported.ORDERED, testConnectionIDA, + ) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is CLOSED", func() { @@ -405,11 +450,14 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { tc.malleate() - proofHeight := suite.chainA.Header.Height + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, channelKey) + if tc.expPass { err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanCloseConfirm( suite.chainB.GetContext(), testPort2, testChannel2, - validProof{}, uint64(proofHeight), + proof, proofHeight+1, ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { diff --git a/x/ibc/04-channel/keeper/keeper_test.go b/x/ibc/04-channel/keeper/keeper_test.go index c65d32dab4c4..f68fe078e21e 100644 --- a/x/ibc/04-channel/keeper/keeper_test.go +++ b/x/ibc/04-channel/keeper/keeper_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "bytes" "errors" "fmt" "testing" @@ -207,10 +208,10 @@ func commitNBlocks(chain *TestChain, n int) { } // nolint: unused -func (suite *KeeperTestSuite) queryProof(key []byte) (commitmenttypes.MerkleProof, int64) { - res := suite.chainB.App.Query(abci.RequestQuery{ +func queryProof(chain *TestChain, key []byte) (commitmenttypes.MerkleProof, uint64) { + res := chain.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), - Height: suite.chainB.App.LastBlockHeight(), + Height: chain.App.LastBlockHeight(), Data: key, Prove: true, }) @@ -219,7 +220,7 @@ func (suite *KeeperTestSuite) queryProof(key []byte) (commitmenttypes.MerkleProo Proof: res.Proof, } - return proof, res.Height + return proof, uint64(res.Height) } type TestChain struct { @@ -403,12 +404,16 @@ func nextHeader(chain *TestChain) ibctmtypes.Header { // TODO: fix tests and replace for real proofs var ( - _ commitmentexported.Proof = validProof{} + _ commitmentexported.Proof = validProof{nil, nil, nil} _ commitmentexported.Proof = invalidProof{} ) type ( - validProof struct{} + validProof struct { + root commitmentexported.Root + path commitmentexported.Path + value []byte + } invalidProof struct{} ) @@ -416,9 +421,15 @@ func (validProof) GetCommitmentType() commitmentexported.Type { return commitmentexported.Merkle } -func (validProof) VerifyMembership( - root commitmentexported.Root, path commitmentexported.Path, value []byte) error { - return nil +func (proof validProof) VerifyMembership( + root commitmentexported.Root, path commitmentexported.Path, value []byte, +) error { + if bytes.Equal(root.GetHash(), proof.root.GetHash()) && + path.String() == proof.path.String() && + bytes.Equal(value, proof.value) { + return nil + } + return errors.New("invalid proof") } func (validProof) VerifyNonMembership(root commitmentexported.Root, path commitmentexported.Path) error { diff --git a/x/ibc/04-channel/keeper/packet_test.go b/x/ibc/04-channel/keeper/packet_test.go index e65932a09a82..ca5239ca5a09 100644 --- a/x/ibc/04-channel/keeper/packet_test.go +++ b/x/ibc/04-channel/keeper/packet_test.go @@ -96,18 +96,23 @@ func (suite *KeeperTestSuite) TestSendPacket() { } func (suite *KeeperTestSuite) TestRecvPacket() { - counterparty := types.NewCounterparty(testPort2, testChannel2) + counterparty := types.NewCounterparty(testPort1, testChannel1) + packetKey := ibctypes.KeyPacketCommitment(testPort2, testChannel2, 1) + var packet exported.PacketI testCases := []testCase{ {"success", func() { suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) - suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) - suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 1) - packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.chainB.updateClient(suite.chainA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDB) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort2, testChannel2, 1) + packet = types.NewPacket(mockSuccessPacket{}, 1, testPort2, testChannel2, counterparty.GetPortID(), counterparty.GetChannelID()) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), testPort2, testChannel2, 1, types.CommitPacket(packet.(types.Packet).Data)) + }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { @@ -149,11 +154,15 @@ func (suite *KeeperTestSuite) TestRecvPacket() { suite.SetupTest() // reset tc.malleate() - proofHeight := uint64(suite.chainA.Header.Height) ctx := suite.chainB.GetContext() + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proof, proofHeight := queryProof(suite.chainA, packetKey) + var err error if tc.expPass { - packet, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, ibctypes.ValidProof{}, proofHeight) + _, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, proof, proofHeight+1) suite.Require().NoError(err) } else { packet, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight) @@ -215,6 +224,7 @@ func (suite *KeeperTestSuite) TestPacketExecuted() { func (suite *KeeperTestSuite) TestAcknowledgePacket() { counterparty := types.NewCounterparty(testPort2, testChannel2) var packet types.Packet + packetKey := ibctypes.KeyPacketAcknowledgement(testPort2, testChannel2, 1) ack := transfertypes.AckDataTransfer{} @@ -222,9 +232,13 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { {"success", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDB) suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, ack.GetBytes()) }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { @@ -267,14 +281,17 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { suite.SetupTest() // reset tc.malleate() + suite.chainA.updateClient(suite.chainB) + suite.chainB.updateClient(suite.chainA) + proof, proofHeight := queryProof(suite.chainA, packetKey) + ctx := suite.chainB.GetContext() - proofHeight := uint64(suite.chainA.Header.Height) if tc.expPass { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, ibctypes.ValidProof{}, proofHeight) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, ibctypes.InvalidProof{}, proofHeight) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1) suite.Require().Error(err) suite.Require().Nil(packetOut) } @@ -284,6 +301,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { func (suite *KeeperTestSuite) TestCleanupPacket() { counterparty := types.NewCounterparty(testPort2, testChannel2) + packetKey := ibctypes.KeyPacketAcknowledgement(testPort2, testChannel2, 1) var ( packet types.Packet nextSeqRecv uint64 @@ -295,10 +313,14 @@ func (suite *KeeperTestSuite) TestCleanupPacket() { {"success", func() { nextSeqRecv = 10 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) + suite.chainA.CreateClient(suite.chainB) suite.chainB.CreateClient(suite.chainA) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionIDB) suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, ack) }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { @@ -356,13 +378,17 @@ func (suite *KeeperTestSuite) TestCleanupPacket() { tc.malleate() ctx := suite.chainB.GetContext() - proofHeight := uint64(suite.chainA.Header.Height) + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proof, proofHeight := queryProof(suite.chainA, packetKey) + if tc.expPass { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, ibctypes.ValidProof{}, proofHeight, nextSeqRecv, ack) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, proof, proofHeight+1, nextSeqRecv, ack) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight, nextSeqRecv, ack) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight+1, nextSeqRecv, ack) suite.Require().Error(err) suite.Require().Nil(packetOut) } diff --git a/x/ibc/04-channel/keeper/timeout_test.go b/x/ibc/04-channel/keeper/timeout_test.go index 917b80adbb6a..5b406e2bdb74 100644 --- a/x/ibc/04-channel/keeper/timeout_test.go +++ b/x/ibc/04-channel/keeper/timeout_test.go @@ -6,16 +6,15 @@ import ( connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) func (suite *KeeperTestSuite) TestTimeoutPacket() { counterparty := types.NewCounterparty(testPort2, testChannel2) + packetKey := ibctypes.KeyPacketAcknowledgement(testPort2, testChannel2, 2) var ( packet types.Packet nextSeqRecv uint64 - proofHeight uint64 = 3 ) testCases := []testCase{ @@ -23,9 +22,11 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { nextSeqRecv = 1 packet = types.NewPacket(newMockTimeoutPacket(1), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.CreateClient(suite.chainA) - proofHeight = uint64(suite.chainA.Header.Height) + suite.chainA.CreateClient(suite.chainB) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionIDB) suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) }, true}, {"channel not found", func() {}, false}, @@ -46,28 +47,24 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"timeout", func() { - proofHeight = 1 packet = types.NewPacket(mockSuccessPacket{}, 10, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet already received ", func() { nextSeqRecv = 2 - proofHeight = 100 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet hasn't been sent", func() { nextSeqRecv = 1 - proofHeight = 100 packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"next seq receive verification failed", func() { nextSeqRecv = 1 - proofHeight = uint64(suite.chainA.Header.Height) packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) @@ -75,7 +72,6 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { }, false}, {"packet ack verification failed", func() { nextSeqRecv = 1 - proofHeight = 100 packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) @@ -89,12 +85,17 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { tc.malleate() ctx := suite.chainB.GetContext() + + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proof, proofHeight := queryProof(suite.chainA, packetKey) + if tc.expPass { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, ibctypes.ValidProof{}, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, proof, proofHeight+1, nextSeqRecv) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight+1, nextSeqRecv) suite.Require().Error(err) suite.Require().Nil(packetOut) } @@ -131,22 +132,23 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { } func (suite *KeeperTestSuite) TestTimeoutOnClose() { + channelKey := ibctypes.KeyChannel(testPort2, testChannel2) + packetKey := ibctypes.KeyPacketAcknowledgement(testPort1, testChannel1, 2) counterparty := types.NewCounterparty(testPort2, testChannel2) var ( packet types.Packet nextSeqRecv uint64 - proofHeight uint64 = 1 - proof commitmentexported.Proof = ibctypes.InvalidProof{} - proofClosed commitmentexported.Proof = ibctypes.InvalidProof{} ) testCases := []testCase{ {"success", func() { packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.CreateClient(suite.chainA) - proofHeight = uint64(suite.chainA.Header.Height) + suite.chainA.CreateClient(suite.chainB) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, exported.UNORDERED, testConnectionIDB) // channel on chainA is closed suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, true}, @@ -171,27 +173,22 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { {"channel verification failed", func() { packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.CreateClient(suite.chainA) - proofHeight = uint64(suite.chainA.Header.Height) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, false}, {"next seq receive verification failed", func() { - proofClosed = ibctypes.ValidProof{} packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.CreateClient(suite.chainA) - proofHeight = uint64(suite.chainA.Header.Height) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, false}, {"packet ack verification failed", func() { - proofClosed = ibctypes.ValidProof{} packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) suite.chainB.CreateClient(suite.chainA) - proofHeight = uint64(suite.chainA.Header.Height) suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) @@ -205,13 +202,18 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.SetupTest() // reset tc.malleate() + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) + proofClosed, proofHeight := queryProof(suite.chainA, channelKey) + proofAckAbsence, _ := queryProof(suite.chainA, packetKey) + ctx := suite.chainB.GetContext() if tc.expPass { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, ibctypes.ValidProof{}, ibctypes.ValidProof{}, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, proofAckAbsence, proofClosed, proofHeight+1, nextSeqRecv) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, proof, proofClosed, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, invalidProof{}, invalidProof{}, proofHeight+1, nextSeqRecv) suite.Require().Error(err) suite.Require().Nil(packetOut) } diff --git a/x/ibc/07-tendermint/types/client_state.go b/x/ibc/07-tendermint/types/client_state.go index 94cb54250942..ca42a181ea8c 100644 --- a/x/ibc/07-tendermint/types/client_state.go +++ b/x/ibc/07-tendermint/types/client_state.go @@ -106,12 +106,15 @@ func (cs ClientState) IsFrozen() bool { // Tendermint client stored on the target machine. func (cs ClientState) VerifyClientConsensusState( cdc *codec.Codec, + provingRoot commitmentexported.Root, height uint64, + counterpartyClientIdentifier string, + consensusHeight uint64, prefix commitmentexported.Prefix, proof commitmentexported.Proof, consensusState clientexported.ConsensusState, ) error { - path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.ConsensusStatePath(cs.GetID(), height)) + path, err := commitmenttypes.ApplyPrefix(prefix, ibctypes.ConsensusStatePath(counterpartyClientIdentifier, consensusHeight)) if err != nil { return err } @@ -120,12 +123,12 @@ func (cs ClientState) VerifyClientConsensusState( return err } - bz, err := cdc.MarshalBinaryBare(consensusState) + bz, err := cdc.MarshalBinaryLengthPrefixed(consensusState) if err != nil { return err } - if err := proof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil { + if err := proof.VerifyMembership(provingRoot, path, bz); err != nil { return sdkerrors.Wrap(clienttypes.ErrFailedClientConsensusStateVerification, err.Error()) } @@ -185,7 +188,7 @@ func (cs ClientState) VerifyChannelState( return err } - bz, err := cdc.MarshalBinaryBare(channel) + bz, err := cdc.MarshalBinaryLengthPrefixed(channel) if err != nil { return err } diff --git a/x/ibc/07-tendermint/types/client_state_test.go b/x/ibc/07-tendermint/types/client_state_test.go index 5eb2705b6cb7..b5d37ca06ad2 100644 --- a/x/ibc/07-tendermint/types/client_state_test.go +++ b/x/ibc/07-tendermint/types/client_state_test.go @@ -25,6 +25,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, chainID, height), @@ -78,7 +79,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { tc := tc err := tc.clientState.VerifyClientConsensusState( - suite.cdc, height, tc.prefix, tc.proof, tc.consensusState, + suite.cdc, tc.consensusState.Root, height, "chainA", tc.consensusState.GetHeight(), tc.prefix, tc.proof, tc.consensusState, ) if tc.expPass { @@ -102,6 +103,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, chainID, height), @@ -184,6 +186,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, height), @@ -263,6 +266,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, height), @@ -342,6 +346,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, chainID, height), @@ -420,6 +425,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, chainID, height), @@ -494,6 +500,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { proof commitmenttypes.MerkleProof expPass bool }{ + // FIXME: uncomment // { // name: "successful verification", // clientState: ibctmtypes.NewClientState(chainID, chainID, height), diff --git a/x/ibc/types/mock.go b/x/ibc/types/mock.go index 43fcd3beadb1..1cbec82adcef 100644 --- a/x/ibc/types/mock.go +++ b/x/ibc/types/mock.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "errors" commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" @@ -10,12 +11,16 @@ import ( // TODO: fix tests and replace for real proofs var ( - _ commitmentexported.Proof = ValidProof{} + _ commitmentexported.Proof = ValidProof{nil, nil, nil} _ commitmentexported.Proof = InvalidProof{} ) type ( - ValidProof struct{} + ValidProof struct { + root commitmentexported.Root + path commitmentexported.Path + value []byte + } InvalidProof struct{} ) @@ -23,9 +28,15 @@ func (ValidProof) GetCommitmentType() commitmentexported.Type { return commitmentexported.Merkle } -func (ValidProof) VerifyMembership( - root commitmentexported.Root, path commitmentexported.Path, value []byte) error { - return nil +func (proof ValidProof) VerifyMembership( + root commitmentexported.Root, path commitmentexported.Path, value []byte, +) error { + if bytes.Equal(root.GetHash(), proof.root.GetHash()) && + path.String() == proof.path.String() && + bytes.Equal(value, proof.value) { + return nil + } + return errors.New("invalid proof") } func (ValidProof) VerifyNonMembership(root commitmentexported.Root, path commitmentexported.Path) error {