From 00742d4156a1cb2117ebd9b2093f6fdcbc13fab2 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 18 Oct 2023 13:22:51 +0300 Subject: [PATCH 01/13] save progress --- .../08-wasm/types/update_test.go | 242 +++--------------- 1 file changed, 42 insertions(+), 200 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index e671cdb6118..8067d40a333 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -3,6 +3,10 @@ package types_test import ( "encoding/base64" + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" @@ -449,208 +453,46 @@ func (suite *TypesTestSuite) TestUpdateStateGrandpa() { } } -// func (suite *TypesTestSuite) TestUpdateStateTendermint() { -// var ( -// path *ibctesting.Path -// clientMessage exported.ClientMessage -// clientStore sdk.KVStore -// consensusHeights []exported.Height -// pruneHeight clienttypes.Height -// prevClientState exported.ClientState -// prevConsensusState exported.ConsensusState -// ) - -// testCases := []struct { -// name string -// malleate func() -// expResult func() -// expPass bool -// }{ -// { -// "success with height later than latest height", func() { -// suite.Require().True(path.EndpointA.GetClientState().GetLatestHeight().LT(height)) -// }, -// func() { -// clientState := path.EndpointA.GetClientState() -// suite.Require().True(clientState.GetLatestHeight().EQ(height)) // new update, updated client state should have changed -// suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) -// }, true, -// }, -// { -// "success with height earlier than latest height", func() { -// // commit a block so the pre-created ClientMessage -// // isn't used to update the client to a newer height -// suite.coordinator.CommitBlock(suite.chainB) -// err := path.EndpointA.UpdateClient() -// suite.Require().NoError(err) - -// suite.Require().True(path.EndpointA.GetClientState().GetLatestHeight().GT(height)) - -// prevClientState = path.EndpointA.GetClientState() -// }, -// func() { -// clientState := path.EndpointA.GetClientState() -// suite.Require().Equal(clientState, prevClientState) // fill in height, no change to client state -// suite.Require().True(clientState.GetLatestHeight().GT(consensusHeights[0])) -// }, true, -// }, -// { -// "success with duplicate header", func() { -// // update client in advance -// err := path.EndpointA.UpdateClient() -// suite.Require().NoError(err) - -// // use the same header which just updated the client -// clientMessage, height, err = path.EndpointA.Chain.ConstructUpdateWasmClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) -// suite.Require().NoError(err) -// suite.Require().Equal(path.EndpointA.GetClientState().GetLatestHeight(), height) - -// prevClientState = path.EndpointA.GetClientState() -// prevConsensusState = path.EndpointA.GetConsensusState(height) -// }, -// func() { -// clientState := path.EndpointA.GetClientState() -// suite.Require().Equal(clientState, prevClientState) -// suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) -// suite.Require().Equal(path.EndpointA.GetConsensusState(height), prevConsensusState) -// }, true, -// }, -// { -// "success with pruned consensus state", func() { -// // this height will be expired and pruned -// err := path.EndpointA.UpdateClient() -// suite.Require().NoError(err) -// pruneHeight = path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) - -// // Increment the time by a week -// suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) - -// // create the consensus state that can be used as trusted height for next update -// err = path.EndpointA.UpdateClient() -// suite.Require().NoError(err) - -// // Increment the time by another week, then update the client. -// // This will cause the first two consensus states to become expired. -// suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) -// err = path.EndpointA.UpdateClient() -// suite.Require().NoError(err) - -// // ensure counterparty state is committed -// suite.coordinator.CommitBlock(suite.chainB) -// clientMessage, height, err = path.EndpointA.Chain.ConstructUpdateWasmClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) -// suite.Require().NoError(err) -// }, -// func() { -// clientState := path.EndpointA.GetClientState() -// suite.Require().True(clientState.GetLatestHeight().EQ(height)) // new update, updated client state should have changed -// suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) - -// // ensure consensus state was pruned -// _, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) -// suite.Require().False(found) -// }, true, -// }, -// { -// "success with pruned consensus state using duplicate header", func() { -// // this height will be expired and pruned -// err := path.EndpointA.UpdateClient() -// suite.Require().NoError(err) -// pruneHeight = path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) - -// // assert that a consensus state exists at the prune height -// consensusState, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) -// suite.Require().True(found) -// suite.Require().NotNil(consensusState) - -// // Increment the time by a week -// suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) - -// // create the consensus state that can be used as trusted height for next update -// err = path.EndpointA.UpdateClient() -// suite.Require().NoError(err) - -// // Increment the time by another week, then update the client. -// // This will cause the first two consensus states to become expired. -// suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) -// err = path.EndpointA.UpdateClient() -// suite.Require().NoError(err) - -// // use the same header which just updated the client -// clientMessage, height, err = path.EndpointA.Chain.ConstructUpdateWasmClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) -// suite.Require().NoError(err) -// }, -// func() { -// clientState := path.EndpointA.GetClientState() -// suite.Require().True(clientState.GetLatestHeight().EQ(height)) // new update, updated client state should have changed -// suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) - -// // ensure consensus state was pruned -// _, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) -// suite.Require().False(found) -// }, true, -// }, -// { -// "invalid ClientMessage type", func() { -// clientMessage = &ibctm.Misbehaviour{} -// }, -// func() {}, -// false, -// }, -// } -// for _, tc := range testCases { -// suite.Run(tc.name, func() { -// suite.SetupWasmTendermint() // reset -// path = ibctesting.NewPath(suite.chainA, suite.chainB) - -// err := path.EndpointA.CreateClient() -// suite.Require().NoError(err) - -// // ensure counterparty state is committed -// suite.coordinator.CommitBlock(suite.chainB) -// clientMessage, height, err = path.EndpointA.Chain.ConstructUpdateWasmClientHeader(path.EndpointA.Counterparty.Chain, path.EndpointA.ClientID) -// suite.Require().NoError(err) - -// tc.malleate() - -// clientState := path.EndpointA.GetClientState() -// clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - -// if tc.expPass { -// consensusHeights = clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) - -// clientMessage, ok := clientMessage.(*types.ClientMessage) -// suite.Require().True(ok) -// var eHeader exported.ClientMessage -// err := suite.chainA.Codec.UnmarshalInterface(clientMessage.Data, &eHeader) -// tmHeader := eHeader.(*ibctm.Header) -// suite.Require().NoError(err) -// expTmConsensusState := &ibctm.ConsensusState{ -// Timestamp: tmHeader.GetTime(), -// Root: commitmenttypes.NewMerkleRoot(tmHeader.Header.GetAppHash()), -// NextValidatorsHash: tmHeader.Header.NextValidatorsHash, -// } -// wasmData, err := suite.chainA.Codec.MarshalInterface(expTmConsensusState) -// suite.Require().NoError(err) -// expWasmConsensusState := &types.ConsensusState{ -// Data: wasmData, -// } - -// bz := clientStore.Get(host.ConsensusStateKey(height)) -// updatedConsensusState := clienttypes.MustUnmarshalConsensusState(suite.chainA.App.AppCodec(), bz) - -// suite.Require().Equal(expWasmConsensusState, updatedConsensusState) +func (suite *TypesTestSuite) TestUpdateStateTendermint() { + var ( + callbackFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success: ", + func() { + callbackFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + respData := + } + }, + true, + }, + { + "failure: invalid ClientMessage type", + func() {}, + false, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupWasmWithMockVM() // reset -// } else { -// suite.Require().Panics(func() { -// clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) -// }) -// } + endpoint := wasmtesting.NewWasmEndpoint(suite.chainA) + err := endpoint.CreateClient() + suite.Require().NoError(err) -// // perform custom checks -// tc.expResult() -// }) -// } -// } + tc.malleate() + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + if tc.expPass { + } else { + } + }) + } +} /* func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviourGrandpa() { var ( From 28950141b40508af88dfc11b204b2843788abdd9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 19 Oct 2023 12:41:33 +0300 Subject: [PATCH 02/13] feat: added working test to iterate on --- .../08-wasm/types/export_test.go | 8 +++ .../08-wasm/types/update_test.go | 67 ++++++++++++++----- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/modules/light-clients/08-wasm/types/export_test.go b/modules/light-clients/08-wasm/types/export_test.go index abccf065c19..5cff91b6d26 100644 --- a/modules/light-clients/08-wasm/types/export_test.go +++ b/modules/light-clients/08-wasm/types/export_test.go @@ -29,4 +29,12 @@ type ( CheckSubstituteAndUpdateStateMsg = checkSubstituteAndUpdateStateMsg VerifyMembershipMsg = verifyMembershipMsg VerifyNonMembershipMsg = verifyNonMembershipMsg + + // Contract response types + EmptyResult = emptyResult + StatusResult = statusResult + ExportMetadataResult = exportMetadataResult + TimestampAtHeightResult = timestampAtHeightResult + CheckForMisbehaviourResult = checkForMisbehaviourResult + UpdateStateResult = updateStateResult ) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index 8067d40a333..d9530a65680 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -2,6 +2,7 @@ package types_test import ( "encoding/base64" + "encoding/json" wasmvm "github.com/CosmWasm/wasmvm" wasmvmtypes "github.com/CosmWasm/wasmvm/types" @@ -453,42 +454,72 @@ func (suite *TypesTestSuite) TestUpdateStateGrandpa() { } } -func (suite *TypesTestSuite) TestUpdateStateTendermint() { - var ( - callbackFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - ) +func (suite *TypesTestSuite) TestUpdateState() { + var callbackFn func(wasmvm.Checksum, wasmvmtypes.Env, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expPanic interface{} + expHeights []exported.Height }{ { - "success: ", + "success: no update", func() { - callbackFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - respData := + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + updateStateResp := types.UpdateStateResult{ + Heights: []clienttypes.Height{}, + } + + resp, err := json.Marshal(updateStateResp) + if err != nil { + return nil, 0, err + } + + return &wasmvmtypes.Response{ + Data: resp, + }, types.DefaultGasUsed, nil } }, - true, - }, - { - "failure: invalid ClientMessage type", - func() {}, - false, + nil, + []exported.Height{}, }, + /* + { + "failure: invalid ClientMessage type", + func() {}, + "TODO", + nil, + }, + */ } for _, tc := range testCases { suite.Run(tc.name, func() { suite.SetupWasmWithMockVM() // reset + clientMsg := &types.ClientMessage{ + Data: []byte{1}, + } + endpoint := wasmtesting.NewWasmEndpoint(suite.chainA) err := endpoint.CreateClient() suite.Require().NoError(err) tc.malleate() - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - if tc.expPass { + + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) + + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) + clientState := endpoint.GetClientState() + + var heights []exported.Height + updateState := func() { + heights = clientState.UpdateState(suite.ctx, suite.chainA.Codec, clientStore, clientMsg) + } + if tc.expPanic == nil { + updateState() + suite.Require().Equal(tc.expHeights, heights) } else { + suite.Require().PanicsWithValue(tc.expPanic, updateState) } }) } From 0ca99e8a61e8b38bd5ad658da7531cf85add8650 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 19 Oct 2023 16:43:41 +0300 Subject: [PATCH 03/13] imp: improved test and added cases --- .../08-wasm/types/update_test.go | 71 ++++++++++++------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index d9530a65680..bc955c37a61 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -3,15 +3,19 @@ package types_test import ( "encoding/base64" "encoding/json" + "fmt" wasmvm "github.com/CosmWasm/wasmvm" wasmvmtypes "github.com/CosmWasm/wasmvm/types" + errorsmod "cosmossdk.io/errors" + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" + tmtypes "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ) func (suite *TypesTestSuite) TestVerifyHeaderGrandpa() { @@ -455,48 +459,64 @@ func (suite *TypesTestSuite) TestUpdateStateGrandpa() { } func (suite *TypesTestSuite) TestUpdateState() { - var callbackFn func(wasmvm.Checksum, wasmvmtypes.Env, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + errMsg := fmt.Errorf("callbackFn error") + var ( + callbackFn func(wasmvm.Checksum, wasmvmtypes.Env, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + clientMsg exported.ClientMessage + ) + testCases := []struct { name string malleate func() - expPanic interface{} + expPanic error expHeights []exported.Height }{ { "success: no update", + func() {}, + nil, + []exported.Height{}, + }, + { + "failure: invalid ClientMessage type", + func() { + clientMsg = &tmtypes.Misbehaviour{} + }, + fmt.Errorf("expected type %T, got %T", (*types.ClientMessage)(nil), (*tmtypes.Misbehaviour)(nil)), + nil, + }, + { + "failure: callbackFn returns error", func() { callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - updateStateResp := types.UpdateStateResult{ - Heights: []clienttypes.Height{}, - } - - resp, err := json.Marshal(updateStateResp) - if err != nil { - return nil, 0, err - } - - return &wasmvmtypes.Response{ - Data: resp, - }, types.DefaultGasUsed, nil + return nil, 0, errMsg } }, + errorsmod.Wrapf(errMsg, "call to wasm contract failed"), nil, - []exported.Height{}, }, - /* - { - "failure: invalid ClientMessage type", - func() {}, - "TODO", - nil, - }, - */ } + for _, tc := range testCases { suite.Run(tc.name, func() { suite.SetupWasmWithMockVM() // reset - clientMsg := &types.ClientMessage{ + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + updateStateResp := types.UpdateStateResult{ + Heights: []clienttypes.Height{}, + } + + resp, err := json.Marshal(updateStateResp) + if err != nil { + return nil, 0, err + } + + return &wasmvmtypes.Response{ + Data: resp, + }, types.DefaultGasUsed, nil + } + + clientMsg = &types.ClientMessage{ Data: []byte{1}, } @@ -515,11 +535,12 @@ func (suite *TypesTestSuite) TestUpdateState() { updateState := func() { heights = clientState.UpdateState(suite.ctx, suite.chainA.Codec, clientStore, clientMsg) } + if tc.expPanic == nil { updateState() suite.Require().Equal(tc.expHeights, heights) } else { - suite.Require().PanicsWithValue(tc.expPanic, updateState) + suite.Require().PanicsWithError(tc.expPanic.Error(), updateState) } }) } From 1de1bca1a9cab0a401f34adb41e91d3b75412d33 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 19 Oct 2023 17:07:25 +0300 Subject: [PATCH 04/13] feat: finished 'TestUpdateState' --- .../08-wasm/types/update_test.go | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index bc955c37a61..ca180d5b838 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -460,22 +460,50 @@ func (suite *TypesTestSuite) TestUpdateStateGrandpa() { func (suite *TypesTestSuite) TestUpdateState() { errMsg := fmt.Errorf("callbackFn error") + mockClientStateBz := []byte("mockClientStateBz") + mockHeight := clienttypes.NewHeight(1, 1) + var ( callbackFn func(wasmvm.Checksum, wasmvmtypes.Env, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) clientMsg exported.ClientMessage ) testCases := []struct { - name string - malleate func() - expPanic error - expHeights []exported.Height + name string + malleate func() + expPanic error + expHeights []exported.Height + expClientState []byte }{ { "success: no update", func() {}, nil, []exported.Height{}, + nil, + }, + { + "success: update client", + func() { + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + store.Set(host.ClientStateKey(), mockClientStateBz) + updateStateResp := types.UpdateStateResult{ + Heights: []clienttypes.Height{mockHeight}, + } + + resp, err := json.Marshal(updateStateResp) + if err != nil { + return nil, 0, err + } + + return &wasmvmtypes.Response{ + Data: resp, + }, types.DefaultGasUsed, nil + } + }, + nil, + []exported.Height{mockHeight}, + mockClientStateBz, }, { "failure: invalid ClientMessage type", @@ -484,6 +512,7 @@ func (suite *TypesTestSuite) TestUpdateState() { }, fmt.Errorf("expected type %T, got %T", (*types.ClientMessage)(nil), (*tmtypes.Misbehaviour)(nil)), nil, + nil, }, { "failure: callbackFn returns error", @@ -494,6 +523,7 @@ func (suite *TypesTestSuite) TestUpdateState() { }, errorsmod.Wrapf(errMsg, "call to wasm contract failed"), nil, + nil, }, } @@ -539,6 +569,11 @@ func (suite *TypesTestSuite) TestUpdateState() { if tc.expPanic == nil { updateState() suite.Require().Equal(tc.expHeights, heights) + + if tc.expClientState != nil { + clientStateBz := clientStore.Get(host.ClientStateKey()) + suite.Require().Equal(tc.expClientState, clientStateBz) + } } else { suite.Require().PanicsWithError(tc.expPanic.Error(), updateState) } From 2be7f92c8043359e57501d5e83d9d6e83fd828c8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 19 Oct 2023 17:41:04 +0300 Subject: [PATCH 05/13] refactor: used suite.store --- modules/light-clients/08-wasm/types/update_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index ca180d5b838..ed902dd27cd 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -558,12 +558,11 @@ func (suite *TypesTestSuite) TestUpdateState() { suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) clientState := endpoint.GetClientState() var heights []exported.Height updateState := func() { - heights = clientState.UpdateState(suite.ctx, suite.chainA.Codec, clientStore, clientMsg) + heights = clientState.UpdateState(suite.ctx, suite.chainA.Codec, suite.store, clientMsg) } if tc.expPanic == nil { @@ -571,7 +570,7 @@ func (suite *TypesTestSuite) TestUpdateState() { suite.Require().Equal(tc.expHeights, heights) if tc.expClientState != nil { - clientStateBz := clientStore.Get(host.ClientStateKey()) + clientStateBz := suite.store.Get(host.ClientStateKey()) suite.Require().Equal(tc.expClientState, clientStateBz) } } else { From 15c4897e88318108895a54423654022c56ce0477 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 19 Oct 2023 18:34:19 +0300 Subject: [PATCH 06/13] imp: fixed linter --- modules/light-clients/08-wasm/types/export_test.go | 4 ++++ modules/light-clients/08-wasm/types/update_test.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/light-clients/08-wasm/types/export_test.go b/modules/light-clients/08-wasm/types/export_test.go index 5cff91b6d26..905adbc19c9 100644 --- a/modules/light-clients/08-wasm/types/export_test.go +++ b/modules/light-clients/08-wasm/types/export_test.go @@ -37,4 +37,8 @@ type ( TimestampAtHeightResult = timestampAtHeightResult CheckForMisbehaviourResult = checkForMisbehaviourResult UpdateStateResult = updateStateResult + + // CallbackFn types + QueryFn = queryFn + SudoFn = sudoFn ) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index ed902dd27cd..01c90d7eb2d 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -464,7 +464,7 @@ func (suite *TypesTestSuite) TestUpdateState() { mockHeight := clienttypes.NewHeight(1, 1) var ( - callbackFn func(wasmvm.Checksum, wasmvmtypes.Env, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + callbackFn types.SudoFn clientMsg exported.ClientMessage ) From 5784e557253f5c3b8f2df7b593479e2c1910be6e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 23 Oct 2023 11:11:06 +0300 Subject: [PATCH 07/13] style: reverted to a different callback registration pattern --- .../08-wasm/types/update_test.go | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index 052b480d044..78e9976f8db 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -477,7 +477,23 @@ func (suite *TypesTestSuite) TestUpdateState() { }{ { "success: no update", - func() {}, + func() { + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + updateStateResp := types.UpdateStateResult{ + Heights: []clienttypes.Height{}, + } + + resp, err := json.Marshal(updateStateResp) + if err != nil { + return nil, 0, err + } + + return &wasmvmtypes.Response{ + Data: resp, + }, types.DefaultGasUsed, nil + } + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) + }, nil, []exported.Height{}, nil, @@ -500,6 +516,7 @@ func (suite *TypesTestSuite) TestUpdateState() { Data: resp, }, types.DefaultGasUsed, nil } + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) }, nil, []exported.Height{mockHeight}, @@ -508,6 +525,10 @@ func (suite *TypesTestSuite) TestUpdateState() { { "failure: invalid ClientMessage type", func() { + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + panic("unreachable") + } + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) clientMsg = &tmtypes.Misbehaviour{} }, fmt.Errorf("expected type %T, got %T", (*types.ClientMessage)(nil), (*tmtypes.Misbehaviour)(nil)), @@ -520,6 +541,7 @@ func (suite *TypesTestSuite) TestUpdateState() { callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { return nil, 0, errMsg } + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) }, errorsmod.Wrapf(errMsg, "call to wasm contract failed"), nil, @@ -531,21 +553,6 @@ func (suite *TypesTestSuite) TestUpdateState() { suite.Run(tc.name, func() { suite.SetupWasmWithMockVM() // reset - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - updateStateResp := types.UpdateStateResult{ - Heights: []clienttypes.Height{}, - } - - resp, err := json.Marshal(updateStateResp) - if err != nil { - return nil, 0, err - } - - return &wasmvmtypes.Response{ - Data: resp, - }, types.DefaultGasUsed, nil - } - clientMsg = &types.ClientMessage{ Data: []byte{1}, } @@ -556,8 +563,6 @@ func (suite *TypesTestSuite) TestUpdateState() { tc.malleate() - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) - clientState := endpoint.GetClientState() var heights []exported.Height From 2eecbe92c50d67215a653c430a3ce4b287e582a0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 23 Oct 2023 11:30:37 +0300 Subject: [PATCH 08/13] style: using errors.New instead of fmt --- modules/light-clients/08-wasm/types/update_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index 78e9976f8db..f544b010bbf 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -3,6 +3,7 @@ package types_test import ( "encoding/base64" "encoding/json" + "errors" "fmt" wasmvm "github.com/CosmWasm/wasmvm" @@ -459,7 +460,7 @@ func (suite *TypesTestSuite) TestUpdateStateGrandpa() { } func (suite *TypesTestSuite) TestUpdateState() { - errMsg := fmt.Errorf("callbackFn error") + errMsg := errors.New("callbackFn error") mockClientStateBz := []byte("mockClientStateBz") mockHeight := clienttypes.NewHeight(1, 1) From 91a3f9748cd7d69b8b054e529a2971215848c821 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 23 Oct 2023 17:16:04 +0300 Subject: [PATCH 09/13] imp: sudoMsg used in tests --- .../light-clients/08-wasm/types/update_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index f544b010bbf..72dee60d73e 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -479,7 +479,11 @@ func (suite *TypesTestSuite) TestUpdateState() { { "success: no update", func() { - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + var msg *types.SudoMsg + err := json.Unmarshal(sudoMsg, &msg) + suite.Require().NoError(err) + updateStateResp := types.UpdateStateResult{ Heights: []clienttypes.Height{}, } @@ -502,8 +506,12 @@ func (suite *TypesTestSuite) TestUpdateState() { { "success: update client", func() { - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - store.Set(host.ClientStateKey(), mockClientStateBz) + callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + var msg *types.SudoMsg + err := json.Unmarshal(sudoMsg, &msg) + suite.Require().NoError(err) + + store.Set(host.ClientStateKey(), msg.UpdateState.ClientMessage.Data) updateStateResp := types.UpdateStateResult{ Heights: []clienttypes.Height{mockHeight}, } @@ -555,7 +563,7 @@ func (suite *TypesTestSuite) TestUpdateState() { suite.SetupWasmWithMockVM() // reset clientMsg = &types.ClientMessage{ - Data: []byte{1}, + Data: mockClientStateBz, } endpoint := wasmtesting.NewWasmEndpoint(suite.chainA) From 8ae1024bc6ff996d044d6b652b63fa4d0b580c17 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 23 Oct 2023 17:22:05 +0300 Subject: [PATCH 10/13] imp: removed unneeded callbackFn --- modules/light-clients/08-wasm/types/update_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index 72dee60d73e..fb0cc510137 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -534,10 +534,7 @@ func (suite *TypesTestSuite) TestUpdateState() { { "failure: invalid ClientMessage type", func() { - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - panic("unreachable") - } - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) + // callbackFn left nil because clientMsg is checked by 08-wasm before callbackFn is called. clientMsg = &tmtypes.Misbehaviour{} }, fmt.Errorf("expected type %T, got %T", (*types.ClientMessage)(nil), (*tmtypes.Misbehaviour)(nil)), From 50ee13764abf9ec7ba9fe90b92ceb11939e17736 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 23 Oct 2023 17:27:41 +0300 Subject: [PATCH 11/13] imp: added more tests on sudoMsg struct --- modules/light-clients/08-wasm/types/update_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index fb0cc510137..35f90891b6f 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -484,6 +484,14 @@ func (suite *TypesTestSuite) TestUpdateState() { err := json.Unmarshal(sudoMsg, &msg) suite.Require().NoError(err) + suite.Require().NotNil(msg.UpdateState) + suite.Require().NotNil(msg.UpdateState.ClientMessage) + suite.Require().Nil(msg.VerifyMembership) + suite.Require().Nil(msg.VerifyNonMembership) + suite.Require().Nil(msg.UpdateStateOnMisbehaviour) + suite.Require().Nil(msg.VerifyUpgradeAndUpdateState) + suite.Require().Nil(msg.CheckSubstituteAndUpdateState) + updateStateResp := types.UpdateStateResult{ Heights: []clienttypes.Height{}, } From ccc0e9192bf6d8a0e3832095e5c64b08904ec50d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 23 Oct 2023 17:57:33 +0300 Subject: [PATCH 12/13] imp: added additional assertion to sudoMsg --- modules/light-clients/08-wasm/types/update_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index 35f90891b6f..d85c7b450e8 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -486,6 +486,7 @@ func (suite *TypesTestSuite) TestUpdateState() { suite.Require().NotNil(msg.UpdateState) suite.Require().NotNil(msg.UpdateState.ClientMessage) + suite.Require().Equal(msg.UpdateState.ClientMessage.Data, mockClientStateBz) suite.Require().Nil(msg.VerifyMembership) suite.Require().Nil(msg.VerifyNonMembership) suite.Require().Nil(msg.UpdateStateOnMisbehaviour) From fe3aa40795a34b2902827cf86b6f317616f98fa9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 25 Oct 2023 00:19:54 +0300 Subject: [PATCH 13/13] imp: reverted back to the previous callback pattern --- .../08-wasm/types/update_test.go | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index d85c7b450e8..cd94c26b7e6 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -464,10 +464,7 @@ func (suite *TypesTestSuite) TestUpdateState() { mockClientStateBz := []byte("mockClientStateBz") mockHeight := clienttypes.NewHeight(1, 1) - var ( - callbackFn types.SudoFn - clientMsg exported.ClientMessage - ) + var clientMsg exported.ClientMessage testCases := []struct { name string @@ -479,7 +476,7 @@ func (suite *TypesTestSuite) TestUpdateState() { { "success: no update", func() { - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { var msg *types.SudoMsg err := json.Unmarshal(sudoMsg, &msg) suite.Require().NoError(err) @@ -505,8 +502,7 @@ func (suite *TypesTestSuite) TestUpdateState() { return &wasmvmtypes.Response{ Data: resp, }, types.DefaultGasUsed, nil - } - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) + }) }, nil, []exported.Height{}, @@ -515,7 +511,7 @@ func (suite *TypesTestSuite) TestUpdateState() { { "success: update client", func() { - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { var msg *types.SudoMsg err := json.Unmarshal(sudoMsg, &msg) suite.Require().NoError(err) @@ -533,8 +529,7 @@ func (suite *TypesTestSuite) TestUpdateState() { return &wasmvmtypes.Response{ Data: resp, }, types.DefaultGasUsed, nil - } - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) + }) }, nil, []exported.Height{mockHeight}, @@ -543,7 +538,7 @@ func (suite *TypesTestSuite) TestUpdateState() { { "failure: invalid ClientMessage type", func() { - // callbackFn left nil because clientMsg is checked by 08-wasm before callbackFn is called. + // SudoCallback left nil because clientMsg is checked by 08-wasm before callbackFn is called. clientMsg = &tmtypes.Misbehaviour{} }, fmt.Errorf("expected type %T, got %T", (*types.ClientMessage)(nil), (*tmtypes.Misbehaviour)(nil)), @@ -553,10 +548,9 @@ func (suite *TypesTestSuite) TestUpdateState() { { "failure: callbackFn returns error", func() { - callbackFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, errMsg - } - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, callbackFn) + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return nil, 0, errors.New("callbackFn error") + }) }, errorsmod.Wrapf(errMsg, "call to wasm contract failed"), nil,