diff --git a/modules/light-clients/08-wasm/keeper/events.go b/modules/light-clients/08-wasm/keeper/events.go index 2ce9a06ab34..8e9801b9e45 100644 --- a/modules/light-clients/08-wasm/keeper/events.go +++ b/modules/light-clients/08-wasm/keeper/events.go @@ -9,7 +9,7 @@ import ( ) // emitStoreWasmCodeEvent emits a store wasm code event -func emitStoreWasmCodeEvent(ctx sdk.Context, checksum []byte) { +func emitStoreWasmCodeEvent(ctx sdk.Context, checksum types.Checksum) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeStoreWasmCode, @@ -23,7 +23,7 @@ func emitStoreWasmCodeEvent(ctx sdk.Context, checksum []byte) { } // emitMigrateContractEvent emits a migrate contract event -func emitMigrateContractEvent(ctx sdk.Context, clientID string, checksum, newChecksum []byte) { +func emitMigrateContractEvent(ctx sdk.Context, clientID string, checksum, newChecksum types.Checksum) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeMigrateContract, diff --git a/modules/light-clients/08-wasm/keeper/export_test.go b/modules/light-clients/08-wasm/keeper/export_test.go deleted file mode 100644 index 6646fe3180a..00000000000 --- a/modules/light-clients/08-wasm/keeper/export_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package keeper - -/* - This file is to allow for unexported functions to be accessible to the testing package. -*/ - -func GenerateWasmChecksum(code []byte) []byte { - return generateWasmChecksum(code) -} diff --git a/modules/light-clients/08-wasm/keeper/genesis.go b/modules/light-clients/08-wasm/keeper/genesis.go index de88b457cb2..4384fb1f599 100644 --- a/modules/light-clients/08-wasm/keeper/genesis.go +++ b/modules/light-clients/08-wasm/keeper/genesis.go @@ -1,8 +1,6 @@ package keeper import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -31,7 +29,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) types.GenesisState { // Grab code from wasmVM and add to genesis state. var genesisState types.GenesisState for _, checksum := range checksums { - code, err := k.wasmVM.GetCode(wasmvmtypes.Checksum(checksum)) + code, err := k.wasmVM.GetCode(checksum) if err != nil { panic(err) } diff --git a/modules/light-clients/08-wasm/keeper/keeper.go b/modules/light-clients/08-wasm/keeper/keeper.go index 3fb6bec81a6..4b65bba05b1 100644 --- a/modules/light-clients/08-wasm/keeper/keeper.go +++ b/modules/light-clients/08-wasm/keeper/keeper.go @@ -2,7 +2,6 @@ package keeper import ( "bytes" - "crypto/sha256" "encoding/hex" "errors" "fmt" @@ -94,11 +93,6 @@ func (k Keeper) GetAuthority() string { return k.authority } -func generateWasmChecksum(code []byte) []byte { - hash := sha256.Sum256(code) - return hash[:] -} - func (k Keeper) storeWasmCode(ctx sdk.Context, code []byte) ([]byte, error) { var err error if types.IsGzip(code) { @@ -110,7 +104,11 @@ func (k Keeper) storeWasmCode(ctx sdk.Context, code []byte) ([]byte, error) { } // Check to see if store already has checksum. - checksum := generateWasmChecksum(code) + checksum, err := types.CreateChecksum(code) + if err != nil { + return nil, errorsmod.Wrap(err, "wasm bytecode checksum failed") + } + if types.HasChecksum(ctx, checksum) { return nil, types.ErrWasmCodeExists } diff --git a/modules/light-clients/08-wasm/keeper/msg_server_test.go b/modules/light-clients/08-wasm/keeper/msg_server_test.go index cdc4f9bfeda..080e1350e63 100644 --- a/modules/light-clients/08-wasm/keeper/msg_server_test.go +++ b/modules/light-clients/08-wasm/keeper/msg_server_test.go @@ -1,9 +1,9 @@ package keeper_test import ( - "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "os" wasmvm "github.com/CosmWasm/wasmvm" @@ -53,11 +53,25 @@ func (suite *KeeperTestSuite) TestMsgStoreCode() { types.ErrWasmCodeExists, }, { - "fails with invalid wasm code", + "fails with zero-length wasm code", func() { msg = types.NewMsgStoreCode(signer, []byte{}) }, - types.ErrWasmEmptyCode, + errors.New("Wasm bytes nil or empty"), + }, + { + "fails with checksum", + func() { + msg = types.NewMsgStoreCode(signer, []byte{0, 1, 3, 4}) + }, + errors.New("Wasm bytes do not not start with Wasm magic number"), + }, + { + "fails with wasm code too large", + func() { + msg = types.NewMsgStoreCode(signer, append(wasmtesting.WasmMagicNumber, []byte(ibctesting.GenerateString(uint(types.MaxWasmByteSize())))...)) + }, + types.ErrWasmCodeTooLarge, }, { "fails with unauthorized signer", @@ -114,7 +128,7 @@ func (suite *KeeperTestSuite) TestMsgStoreCode() { suite.Require().Contains(events, evt) } } else { - suite.Require().ErrorIs(err, tc.expError) + suite.Require().Contains(err.Error(), tc.expError.Error()) suite.Require().Nil(res) suite.Require().Empty(events) } @@ -123,9 +137,11 @@ func (suite *KeeperTestSuite) TestMsgStoreCode() { } func (suite *KeeperTestSuite) TestMsgMigrateContract() { - oldChecksum := sha256.Sum256(wasmtesting.Code) + oldChecksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) - newByteCode := []byte("MockByteCode-TestMsgMigrateContract") + newByteCode := wasmtesting.WasmMagicNumber + newByteCode = append(newByteCode, []byte("MockByteCode-TestMsgMigrateContract")...) govAcc := authtypes.NewModuleAddress(govtypes.ModuleName).String() @@ -175,7 +191,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { { "failure: same checksum", func() { - msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, oldChecksum[:], []byte("{}")) + msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, oldChecksum, []byte("{}")) suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { panic("unreachable") @@ -272,7 +288,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { sdk.NewEvent( "migrate_contract", sdk.NewAttribute(types.AttributeKeyClientID, defaultWasmClientID), - sdk.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(oldChecksum[:])), + sdk.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(oldChecksum)), sdk.NewAttribute(types.AttributeKeyNewChecksum, hex.EncodeToString(newChecksum)), ), sdk.NewEvent( @@ -293,7 +309,8 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { } func (suite *KeeperTestSuite) TestMsgRemoveChecksum() { - checksum := sha256.Sum256(wasmtesting.Code) + checksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) govAcc := authtypes.NewModuleAddress(govtypes.ModuleName).String() @@ -310,7 +327,7 @@ func (suite *KeeperTestSuite) TestMsgRemoveChecksum() { { "success", func() { - msg = types.NewMsgRemoveChecksum(govAcc, checksum[:]) + msg = types.NewMsgRemoveChecksum(govAcc, checksum) expChecksums = []types.Checksum{} }, @@ -319,16 +336,20 @@ func (suite *KeeperTestSuite) TestMsgRemoveChecksum() { { "success: many checksums", func() { - msg = types.NewMsgRemoveChecksum(govAcc, checksum[:]) + msg = types.NewMsgRemoveChecksum(govAcc, checksum) expChecksums = []types.Checksum{} for i := 0; i < 20; i++ { - checksum := sha256.Sum256([]byte{byte(i)}) - err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), checksum[:]) + mockCode := []byte{byte(i)} + mockCode = append(wasmtesting.WasmMagicNumber, mockCode...) + checksum, err := types.CreateChecksum(mockCode) + suite.Require().NoError(err) + + err = ibcwasm.Checksums.Set(suite.chainA.GetContext(), checksum) suite.Require().NoError(err) - expChecksums = append(expChecksums, checksum[:]) + expChecksums = append(expChecksums, checksum) } }, nil, @@ -343,14 +364,14 @@ func (suite *KeeperTestSuite) TestMsgRemoveChecksum() { { "failure: unauthorized signer", func() { - msg = types.NewMsgRemoveChecksum(suite.chainA.SenderAccount.GetAddress().String(), checksum[:]) + msg = types.NewMsgRemoveChecksum(suite.chainA.SenderAccount.GetAddress().String(), checksum) }, ibcerrors.ErrUnauthorized, }, { "failure: code has could not be unpinned", func() { - msg = types.NewMsgRemoveChecksum(govAcc, checksum[:]) + msg = types.NewMsgRemoveChecksum(govAcc, checksum) suite.mockVM.UnpinFn = func(_ wasmvm.Checksum) error { return wasmtesting.ErrMockVM diff --git a/modules/light-clients/08-wasm/keeper/snapshotter.go b/modules/light-clients/08-wasm/keeper/snapshotter.go index 91540d27aad..e48baff5678 100644 --- a/modules/light-clients/08-wasm/keeper/snapshotter.go +++ b/modules/light-clients/08-wasm/keeper/snapshotter.go @@ -4,8 +4,6 @@ import ( "encoding/hex" "io" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" - errorsmod "cosmossdk.io/errors" snapshot "cosmossdk.io/store/snapshots/types" storetypes "cosmossdk.io/store/types" @@ -74,7 +72,7 @@ func (ws *WasmSnapshotter) SnapshotExtension(height uint64, payloadWriter snapsh } for _, checksum := range checksums { - wasmCode, err := ws.keeper.wasmVM.GetCode(wasmvmtypes.Checksum(checksum)) + wasmCode, err := ws.keeper.wasmVM.GetCode(checksum) if err != nil { return err } diff --git a/modules/light-clients/08-wasm/keeper/snapshotter_test.go b/modules/light-clients/08-wasm/keeper/snapshotter_test.go index ccfb63e818e..6cb6d81e769 100644 --- a/modules/light-clients/08-wasm/keeper/snapshotter_test.go +++ b/modules/light-clients/08-wasm/keeper/snapshotter_test.go @@ -9,14 +9,13 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing/simapp" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ) func (suite *KeeperTestSuite) TestSnapshotter() { - gzippedContract, err := types.GzipIt([]byte("gzipped-contract")) + gzippedContract, err := types.GzipIt(append(wasmtesting.WasmMagicNumber, []byte("gzipped-contract")...)) suite.Require().NoError(err) testCases := []struct { @@ -110,7 +109,10 @@ func (suite *KeeperTestSuite) TestSnapshotter() { resp, err := destWasmClientApp.WasmClientKeeper.Code(ctx, &types.QueryCodeRequest{Checksum: hex.EncodeToString(checksum)}) suite.Require().NoError(err) - allDestAppChecksumsInWasmVMStore = append(allDestAppChecksumsInWasmVMStore, keeper.GenerateWasmChecksum(resp.Data)...) + checksum, err := types.CreateChecksum(resp.Data) + suite.Require().NoError(err) + + allDestAppChecksumsInWasmVMStore = append(allDestAppChecksumsInWasmVMStore, checksum...) } suite.Require().Equal(srcChecksumCodes, allDestAppChecksumsInWasmVMStore) diff --git a/modules/light-clients/08-wasm/testing/mock_engine.go b/modules/light-clients/08-wasm/testing/mock_engine.go index 202bb901ff0..82191bdbf42 100644 --- a/modules/light-clients/08-wasm/testing/mock_engine.go +++ b/modules/light-clients/08-wasm/testing/mock_engine.go @@ -1,7 +1,6 @@ package testing import ( - "crypto/sha256" "encoding/binary" "encoding/json" "errors" @@ -58,8 +57,7 @@ func NewMockWasmEngine() *MockWasmEngine { // Set up default behavior for Store/Pin/Get m.StoreCodeFn = func(code wasmvm.WasmCode) (wasmvm.Checksum, error) { - hash := sha256.Sum256(code) - checkSum := wasmvm.Checksum(hash[:]) + checkSum, _ := types.CreateChecksum(code) m.storedContracts[binary.LittleEndian.Uint32(checkSum)] = code return checkSum, nil diff --git a/modules/light-clients/08-wasm/testing/values.go b/modules/light-clients/08-wasm/testing/values.go index e9ec6d49538..dd54a4e3f3b 100644 --- a/modules/light-clients/08-wasm/testing/values.go +++ b/modules/light-clients/08-wasm/testing/values.go @@ -11,7 +11,8 @@ import ( var ( // Represents the code of the wasm contract used in the tests with a mock vm. - Code = []byte("01234567012345670123456701234567") + WasmMagicNumber = []byte("\x00\x61\x73\x6D") + Code = append(WasmMagicNumber, []byte("0123456780123456780123456780")...) contractClientState = []byte{1} contractConsensusState = []byte{2} MockClientStateBz = []byte("client-state-data") @@ -26,7 +27,7 @@ var ( ) // CreateMockClientStateBz returns valid client state bytes for use in tests. -func CreateMockClientStateBz(cdc codec.BinaryCodec, checksum []byte) []byte { +func CreateMockClientStateBz(cdc codec.BinaryCodec, checksum types.Checksum) []byte { mockClientSate := types.NewClientState([]byte{1}, checksum, clienttypes.NewHeight(2000, 2)) return clienttypes.MustMarshalClientState(cdc, mockClientSate) } diff --git a/modules/light-clients/08-wasm/testing/wasm_endpoint.go b/modules/light-clients/08-wasm/testing/wasm_endpoint.go index 3e9cc09c697..9a125051ed6 100644 --- a/modules/light-clients/08-wasm/testing/wasm_endpoint.go +++ b/modules/light-clients/08-wasm/testing/wasm_endpoint.go @@ -1,8 +1,6 @@ package testing import ( - "crypto/sha256" - "github.com/stretchr/testify/require" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -28,8 +26,10 @@ func NewWasmEndpoint(chain *ibctesting.TestChain) *WasmEndpoint { // The client and consensus states are represented by byte slices // and the starting height is 1. func (endpoint *WasmEndpoint) CreateClient() error { - checksum := sha256.Sum256(Code) - clientState := types.NewClientState(contractClientState, checksum[:], clienttypes.NewHeight(0, 1)) + checksum, err := types.CreateChecksum(Code) + require.NoError(endpoint.Chain.TB, err) + + clientState := types.NewClientState(contractClientState, checksum, clienttypes.NewHeight(0, 1)) consensusState := types.NewConsensusState(contractConsensusState, 0) msg, err := clienttypes.NewMsgCreateClient( diff --git a/modules/light-clients/08-wasm/types/client_state_test.go b/modules/light-clients/08-wasm/types/client_state_test.go index 440ea360e91..d4a4f5410f7 100644 --- a/modules/light-clients/08-wasm/types/client_state_test.go +++ b/modules/light-clients/08-wasm/types/client_state_test.go @@ -1,7 +1,6 @@ package types_test import ( - "crypto/sha256" "encoding/json" "time" @@ -306,8 +305,10 @@ func (suite *TypesTestSuite) TestInitialize() { suite.Run(tc.name, func() { suite.SetupWasmWithMockVM() - checksum := sha256.Sum256(wasmtesting.Code) - clientState = types.NewClientState([]byte{1}, checksum[:], clienttypes.NewHeight(0, 1)) + checksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) + + clientState = types.NewClientState([]byte{1}, checksum, clienttypes.NewHeight(0, 1)) consensusState = types.NewConsensusState([]byte{2}, 0) clientID := suite.chainA.App.GetIBCKeeper().ClientKeeper.GenerateClientIdentifier(suite.chainA.GetContext(), clientState.ClientType()) @@ -315,7 +316,7 @@ func (suite *TypesTestSuite) TestInitialize() { tc.malleate() - err := clientState.Initialize(suite.chainA.GetContext(), suite.chainA.Codec, clientStore, consensusState) + err = clientState.Initialize(suite.chainA.GetContext(), suite.chainA.Codec, clientStore, consensusState) expPass := tc.expError == nil if expPass { diff --git a/modules/light-clients/08-wasm/types/migrate_contract_test.go b/modules/light-clients/08-wasm/types/migrate_contract_test.go index cf96c923c56..fbaeb4deed3 100644 --- a/modules/light-clients/08-wasm/types/migrate_contract_test.go +++ b/modules/light-clients/08-wasm/types/migrate_contract_test.go @@ -1,7 +1,6 @@ package types_test import ( - "crypto/sha256" "encoding/hex" "encoding/json" @@ -17,8 +16,8 @@ import ( func (suite *TypesTestSuite) TestMigrateContract() { var ( - oldHash [32]byte - newHash [32]byte + oldHash []byte + newHash []byte payload []byte expClientState *types.ClientState ) @@ -31,11 +30,11 @@ func (suite *TypesTestSuite) TestMigrateContract() { { "success: no update to client state", func() { - err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash[:]) + err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash) suite.Require().NoError(err) payload = []byte{1} - expChecksum := wasmvmtypes.ForceNewChecksum(hex.EncodeToString(newHash[:])) + expChecksum := wasmvmtypes.ForceNewChecksum(hex.EncodeToString(newHash)) suite.mockVM.MigrateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, msg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { suite.Require().Equal(expChecksum, checksum) @@ -54,7 +53,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { "success: update client state", func() { suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - expClientState = types.NewClientState([]byte{1}, newHash[:], clienttypes.NewHeight(2000, 2)) + expClientState = types.NewClientState([]byte{1}, newHash, clienttypes.NewHeight(2000, 2)) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), expClientState)) data, err := json.Marshal(types.EmptyResult{}) @@ -79,7 +78,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { { "failure: checksum not found", func() { - err := ibcwasm.Checksums.Remove(suite.chainA.GetContext(), newHash[:]) + err := ibcwasm.Checksums.Remove(suite.chainA.GetContext(), newHash) suite.Require().NoError(err) }, types.ErrWasmChecksumNotFound, @@ -87,7 +86,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { { "failure: contract returns error", func() { - err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash[:]) + err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash) suite.Require().NoError(err) suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { @@ -103,10 +102,13 @@ func (suite *TypesTestSuite) TestMigrateContract() { suite.Run(tc.name, func() { suite.SetupWasmWithMockVM() - oldHash = sha256.Sum256(wasmtesting.Code) - newHash = sha256.Sum256([]byte{1, 2, 3}) + var err error + oldHash, err = types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) + newHash, err = types.CreateChecksum(append(wasmtesting.WasmMagicNumber, []byte{1, 2, 3}...)) + suite.Require().NoError(err) - err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash[:]) + err = ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash) suite.Require().NoError(err) endpointA := wasmtesting.NewWasmEndpoint(suite.chainA) @@ -121,7 +123,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { tc.malleate() - err = clientState.MigrateContract(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, endpointA.ClientID, newHash[:], payload) + err = clientState.MigrateContract(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, endpointA.ClientID, newHash, payload) // updated client state clientState, ok = endpointA.GetClientState().(*types.ClientState) diff --git a/modules/light-clients/08-wasm/types/msgs_test.go b/modules/light-clients/08-wasm/types/msgs_test.go index f3647cb2fe6..f63a6190e2f 100644 --- a/modules/light-clients/08-wasm/types/msgs_test.go +++ b/modules/light-clients/08-wasm/types/msgs_test.go @@ -1,7 +1,6 @@ package types_test import ( - "crypto/sha256" "testing" "github.com/stretchr/testify/require" @@ -90,7 +89,8 @@ func (suite *TypesTestSuite) TestMsgStoreCodeGetSigners() { func TestMsgMigrateContractValidateBasic(t *testing.T) { signer := sdk.AccAddress(ibctesting.TestAccAddress).String() - validChecksum := sha256.Sum256(wasmtesting.Code) + validChecksum, err := types.CreateChecksum(wasmtesting.Code) + require.NoError(t, err, t.Name()) validMigrateMsg := []byte("{}") testCases := []struct { @@ -100,22 +100,22 @@ func TestMsgMigrateContractValidateBasic(t *testing.T) { }{ { "success: valid signer address, valid checksum, valid migrate msg", - types.NewMsgMigrateContract(signer, defaultWasmClientID, validChecksum[:], validMigrateMsg), + types.NewMsgMigrateContract(signer, defaultWasmClientID, validChecksum, validMigrateMsg), nil, }, { "failure: invalid signer address", - types.NewMsgMigrateContract(ibctesting.InvalidID, defaultWasmClientID, validChecksum[:], validMigrateMsg), + types.NewMsgMigrateContract(ibctesting.InvalidID, defaultWasmClientID, validChecksum, validMigrateMsg), ibcerrors.ErrInvalidAddress, }, { "failure: clientID is not a valid client identifier", - types.NewMsgMigrateContract(signer, ibctesting.InvalidID, validChecksum[:], validMigrateMsg), + types.NewMsgMigrateContract(signer, ibctesting.InvalidID, validChecksum, validMigrateMsg), host.ErrInvalidID, }, { "failure: clientID is not a wasm client identifier", - types.NewMsgMigrateContract(signer, ibctesting.FirstClientID, validChecksum[:], validMigrateMsg), + types.NewMsgMigrateContract(signer, ibctesting.FirstClientID, validChecksum, validMigrateMsg), host.ErrInvalidID, }, { @@ -135,12 +135,12 @@ func TestMsgMigrateContractValidateBasic(t *testing.T) { }, { "failure: migrateMsg is nil", - types.NewMsgMigrateContract(signer, defaultWasmClientID, validChecksum[:], nil), + types.NewMsgMigrateContract(signer, defaultWasmClientID, validChecksum, nil), errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "migrate message cannot be empty"), }, { "failure: migrateMsg is empty", - types.NewMsgMigrateContract(signer, defaultWasmClientID, validChecksum[:], []byte("")), + types.NewMsgMigrateContract(signer, defaultWasmClientID, validChecksum, []byte("")), errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "migrate message cannot be empty"), }, } @@ -159,7 +159,8 @@ func TestMsgMigrateContractValidateBasic(t *testing.T) { } func (suite *TypesTestSuite) TestMsgMigrateContractGetSigners() { - checksum := sha256.Sum256(wasmtesting.Code) + checksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) testCases := []struct { name string @@ -176,7 +177,7 @@ func (suite *TypesTestSuite) TestMsgMigrateContractGetSigners() { suite.SetupWasmWithMockVM() address := tc.address - msg := types.NewMsgMigrateContract(address.String(), defaultWasmClientID, checksum[:], []byte("{}")) + msg := types.NewMsgMigrateContract(address.String(), defaultWasmClientID, checksum, []byte("{}")) signers, _, err := GetSimApp(suite.chainA).AppCodec().GetMsgV1Signers(msg) if tc.expPass { @@ -191,7 +192,8 @@ func (suite *TypesTestSuite) TestMsgMigrateContractGetSigners() { func TestMsgRemoveChecksumValidateBasic(t *testing.T) { signer := sdk.AccAddress(ibctesting.TestAccAddress).String() - checksum := sha256.Sum256(wasmtesting.Code) + checksum, err := types.CreateChecksum(wasmtesting.Code) + require.NoError(t, err, t.Name()) testCases := []struct { name string @@ -200,7 +202,7 @@ func TestMsgRemoveChecksumValidateBasic(t *testing.T) { }{ { "success: valid signer address, valid length checksum", - types.NewMsgRemoveChecksum(signer, checksum[:]), + types.NewMsgRemoveChecksum(signer, checksum), nil, }, { @@ -215,7 +217,7 @@ func TestMsgRemoveChecksumValidateBasic(t *testing.T) { }, { "failure: signer is invalid", - types.NewMsgRemoveChecksum(ibctesting.InvalidID, checksum[:]), + types.NewMsgRemoveChecksum(ibctesting.InvalidID, checksum), ibcerrors.ErrInvalidAddress, }, } @@ -234,7 +236,8 @@ func TestMsgRemoveChecksumValidateBasic(t *testing.T) { } func (suite *TypesTestSuite) TestMsgRemoveChecksumGetSigners() { - checksum := sha256.Sum256(wasmtesting.Code) + checksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) testCases := []struct { name string @@ -251,7 +254,7 @@ func (suite *TypesTestSuite) TestMsgRemoveChecksumGetSigners() { suite.SetupWasmWithMockVM() address := tc.address - msg := types.NewMsgRemoveChecksum(address.String(), checksum[:]) + msg := types.NewMsgRemoveChecksum(address.String(), checksum) signers, _, err := GetSimApp(suite.chainA).AppCodec().GetMsgV1Signers(msg) if tc.expPass { diff --git a/modules/light-clients/08-wasm/types/types_test.go b/modules/light-clients/08-wasm/types/types_test.go index 49d2e2595a0..8f882f64aaa 100644 --- a/modules/light-clients/08-wasm/types/types_test.go +++ b/modules/light-clients/08-wasm/types/types_test.go @@ -37,7 +37,7 @@ type TypesTestSuite struct { chainA *ibctesting.TestChain mockVM *wasmtesting.MockWasmEngine - checksum []byte + checksum types.Checksum } func TestWasmTestSuite(t *testing.T) { @@ -113,7 +113,7 @@ func (suite *TypesTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[s } // storeWasmCode stores the wasm code on chain and returns the checksum. -func storeWasmCode(suite *TypesTestSuite, wasmCode []byte) []byte { +func storeWasmCode(suite *TypesTestSuite, wasmCode []byte) types.Checksum { ctx := suite.chainA.GetContext().WithBlockGasMeter(storetypes.NewInfiniteGasMeter()) msg := types.NewMsgStoreCode(authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmCode) diff --git a/modules/light-clients/08-wasm/types/validation.go b/modules/light-clients/08-wasm/types/validation.go index c5b15474b33..843d560ca46 100644 --- a/modules/light-clients/08-wasm/types/validation.go +++ b/modules/light-clients/08-wasm/types/validation.go @@ -31,7 +31,7 @@ func MaxWasmByteSize() uint64 { } // ValidateWasmChecksum validates that the checksum is of the correct length -func ValidateWasmChecksum(checksum []byte) error { +func ValidateWasmChecksum(checksum Checksum) error { lenChecksum := len(checksum) if lenChecksum == 0 { return errorsmod.Wrap(ErrInvalidChecksum, "checksum cannot be empty") diff --git a/modules/light-clients/08-wasm/types/validation_test.go b/modules/light-clients/08-wasm/types/validation_test.go index ff9c44bf27b..b8c42c7a9e0 100644 --- a/modules/light-clients/08-wasm/types/validation_test.go +++ b/modules/light-clients/08-wasm/types/validation_test.go @@ -2,7 +2,6 @@ package types_test import ( "crypto/rand" - "crypto/sha256" "os" "testing" @@ -10,6 +9,7 @@ import ( 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" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -65,7 +65,7 @@ func TestValidateWasmCode(t *testing.T) { } func TestValidateWasmChecksum(t *testing.T) { - var checksum []byte + var checksum types.Checksum testCases := []struct { name string @@ -75,9 +75,9 @@ func TestValidateWasmChecksum(t *testing.T) { { "success", func() { - code, _ := os.ReadFile("../test_data/ics10_grandpa_cw.wasm.gz") - hash := sha256.Sum256(code) - checksum = hash[:] + hash, err := types.CreateChecksum(wasmtesting.Code) + require.NoError(t, err, t.Name()) + checksum = hash }, nil, }, diff --git a/modules/light-clients/08-wasm/types/vm.go b/modules/light-clients/08-wasm/types/vm.go index d8af29be4d4..b23710139bd 100644 --- a/modules/light-clients/08-wasm/types/vm.go +++ b/modules/light-clients/08-wasm/types/vm.go @@ -32,7 +32,7 @@ var ( ) // instantiateContract calls vm.Instantiate with appropriate arguments. -func instantiateContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum []byte, msg []byte) (*wasmvmtypes.Response, error) { +func instantiateContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) @@ -55,7 +55,7 @@ func instantiateContract(ctx sdk.Context, clientStore storetypes.KVStore, checks } // callContract calls vm.Sudo with internally constructed gas meter and environment. -func callContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum []byte, msg []byte) (*wasmvmtypes.Response, error) { +func callContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) @@ -73,7 +73,7 @@ func callContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum []by } // migrateContract calls vm.Migrate with internally constructed gas meter and environment. -func migrateContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum []byte, msg []byte) (*wasmvmtypes.Response, error) { +func migrateContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) @@ -87,7 +87,7 @@ func migrateContract(ctx sdk.Context, clientID string, clientStore storetypes.KV } // queryContract calls vm.Query. -func queryContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum []byte, msg []byte) ([]byte, error) { +func queryContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) ([]byte, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) diff --git a/modules/light-clients/08-wasm/types/wasm.go b/modules/light-clients/08-wasm/types/wasm.go index fa6e3d38c3f..cfec1c03b2b 100644 --- a/modules/light-clients/08-wasm/types/wasm.go +++ b/modules/light-clients/08-wasm/types/wasm.go @@ -3,11 +3,23 @@ package types import ( "context" + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" ) // Checksum is a type alias used for wasm byte code checksums. -type Checksum []byte +type Checksum = wasmvmtypes.Checksum + +// CreateChecksum creates a sha256 checksum from the given wasm code, it forwards the +// call to the wasmvm package. The code is checked for the following conditions: +// - code length is zero. +// - code length is less than 4 bytes (magic number length). +// - code does not start with the wasm magic number. +func CreateChecksum(code []byte) (Checksum, error) { + return wasmvm.CreateChecksum(code) +} // GetAllChecksums is a helper to get all checksums from the store. // It returns an empty slice if no checksums are found diff --git a/modules/light-clients/08-wasm/types/wasm_test.go b/modules/light-clients/08-wasm/types/wasm_test.go index 27325f7822a..65b9b6574c5 100644 --- a/modules/light-clients/08-wasm/types/wasm_test.go +++ b/modules/light-clients/08-wasm/types/wasm_test.go @@ -1,8 +1,6 @@ package types_test import ( - "crypto/sha256" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -28,8 +26,9 @@ func (suite *TypesTestSuite) TestGetChecksums() { }, func(checksums []types.Checksum) { suite.Require().Len(checksums, 1) - expectedChecksum := sha256.Sum256(wasmtesting.Code) - suite.Require().Equal(types.Checksum(expectedChecksum[:]), checksums[0]) + expectedChecksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) + suite.Require().Equal(expectedChecksum, checksums[0]) }, }, {