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 305dfce20ff..accf1824cc3 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 97034241060..9b2c23ede4f 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" @@ -90,11 +89,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) { @@ -106,7 +100,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, k.cdc, 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 42ad23a046a..4fb9b54230d 100644 --- a/modules/light-clients/08-wasm/keeper/msg_server_test.go +++ b/modules/light-clients/08-wasm/keeper/msg_server_test.go @@ -1,10 +1,11 @@ package keeper_test import ( - "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "os" + "strings" wasmvm "github.com/CosmWasm/wasmvm" wasmvmtypes "github.com/CosmWasm/wasmvm/types" @@ -13,14 +14,15 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "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" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ibctesting "github.com/cosmos/ibc-go/v7/testing" + + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" ) func (suite *KeeperTestSuite) TestMsgStoreCode() { @@ -53,11 +55,31 @@ 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() { + var sb strings.Builder + for i := 0; i < int(types.MaxWasmByteSize()); i++ { + err := sb.WriteByte(byte(i)) + suite.Require().NoError(err) + } + + msg = types.NewMsgStoreCode(signer, append(wasmtesting.WasmMagicNumber, []byte(sb.String())...)) + }, + types.ErrWasmCodeTooLarge, }, { "fails with unauthorized signer", @@ -114,7 +136,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 +145,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 +199,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 +296,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 +317,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 +335,7 @@ func (suite *KeeperTestSuite) TestMsgRemoveChecksum() { { "success", func() { - msg = types.NewMsgRemoveChecksum(govAcc, checksum[:]) + msg = types.NewMsgRemoveChecksum(govAcc, checksum) expChecksums = []types.Checksum{} }, @@ -319,17 +344,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)}) + mockCode := []byte{byte(i)} + mockCode = append(wasmtesting.WasmMagicNumber, mockCode...) + checksum, err := types.CreateChecksum(mockCode) + suite.Require().NoError(err) - err := types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), checksum[:]) + err = types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), checksum) suite.Require().NoError(err) - expChecksums = append(expChecksums, checksum[:]) + expChecksums = append(expChecksums, checksum) } }, nil, @@ -344,14 +372,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 989ff852d3f..77942608e4c 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 "github.com/cosmos/cosmos-sdk/snapshots/types" @@ -73,7 +71,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 6c6c86715e9..d0b14cc3772 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 { @@ -109,7 +108,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 ef23c2f79cc..6899a46c7e8 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 58069f9c0e0..2f5d0533d07 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.T, 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 3a374696a88..22c4c127a31 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 c3b99db825d..59a6a4dfdbf 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 := types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), newHash[:]) + err := types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), 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 := types.RemoveChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), newHash[:]) + err := types.RemoveChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), newHash) suite.Require().NoError(err) }, types.ErrWasmChecksumNotFound, @@ -87,7 +86,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { { "failure: contract returns error", func() { - err := types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), newHash[:]) + err := types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), 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 := types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), newHash[:]) + err = types.AddChecksum(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), ibcwasm.GetWasmStoreKey(), 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 fd83214bf0c..48d9c61d2a0 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" @@ -86,7 +85,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 { @@ -96,22 +96,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, }, { @@ -131,12 +131,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"), }, } @@ -155,7 +155,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 @@ -183,7 +184,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 @@ -192,7 +194,7 @@ func TestMsgRemoveChecksumValidateBasic(t *testing.T) { }{ { "success: valid signer address, valid length checksum", - types.NewMsgRemoveChecksum(signer, checksum[:]), + types.NewMsgRemoveChecksum(signer, checksum), nil, }, { @@ -207,7 +209,7 @@ func TestMsgRemoveChecksumValidateBasic(t *testing.T) { }, { "failure: signer is invalid", - types.NewMsgRemoveChecksum(ibctesting.InvalidID, checksum[:]), + types.NewMsgRemoveChecksum(ibctesting.InvalidID, checksum), ibcerrors.ErrInvalidAddress, }, } @@ -226,7 +228,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 diff --git a/modules/light-clients/08-wasm/types/types_test.go b/modules/light-clients/08-wasm/types/types_test.go index 1b58d3d7382..978120cb2f2 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 23b0e565178..3b42341f14c 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 57e745d28d2..bc5aa145c8a 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" @@ -14,6 +13,8 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" + + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" ) func TestValidateWasmCode(t *testing.T) { @@ -65,7 +66,7 @@ func TestValidateWasmCode(t *testing.T) { } func TestValidateWasmChecksum(t *testing.T) { - var checksum []byte + var checksum types.Checksum testCases := []struct { name string @@ -75,9 +76,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 665f3dc351c..95ca11416b1 100644 --- a/modules/light-clients/08-wasm/types/vm.go +++ b/modules/light-clients/08-wasm/types/vm.go @@ -14,10 +14,11 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" + + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" ) var ( @@ -31,7 +32,7 @@ var ( ) // instantiateContract calls vm.Instantiate with appropriate arguments. -func instantiateContract(ctx sdk.Context, clientStore sdk.KVStore, checksum []byte, msg []byte) (*wasmvmtypes.Response, error) { +func instantiateContract(ctx sdk.Context, clientStore sdk.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) @@ -54,7 +55,7 @@ func instantiateContract(ctx sdk.Context, clientStore sdk.KVStore, checksum []by } // callContract calls vm.Sudo with internally constructed gas meter and environment. -func callContract(ctx sdk.Context, clientStore sdk.KVStore, checksum []byte, msg []byte) (*wasmvmtypes.Response, error) { +func callContract(ctx sdk.Context, clientStore sdk.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) @@ -72,7 +73,7 @@ func callContract(ctx sdk.Context, clientStore sdk.KVStore, checksum []byte, msg } // migrateContract calls vm.Migrate with internally constructed gas meter and environment. -func migrateContract(ctx sdk.Context, clientID string, clientStore sdk.KVStore, checksum []byte, msg []byte) (*wasmvmtypes.Response, error) { +func migrateContract(ctx sdk.Context, clientID string, clientStore sdk.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) gasLimit := VMGasRegister.runtimeGasForContract(ctx) @@ -86,7 +87,7 @@ func migrateContract(ctx sdk.Context, clientID string, clientStore sdk.KVStore, } // queryContract calls vm.Query. -func queryContract(ctx sdk.Context, clientStore sdk.KVStore, checksum []byte, msg []byte) ([]byte, error) { +func queryContract(ctx sdk.Context, clientStore sdk.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 dad54a53a82..0ae1a4c5737 100644 --- a/modules/light-clients/08-wasm/types/wasm.go +++ b/modules/light-clients/08-wasm/types/wasm.go @@ -4,14 +4,27 @@ import ( "bytes" "slices" + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/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 @@ -29,7 +42,13 @@ func GetAllChecksums(ctx sdk.Context, cdc codec.BinaryCodec) ([]Checksum, error) if err != nil { return []Checksum{}, err } - return hashes.Checksums, nil + + var checksums []Checksum + for _, checksum := range hashes.Checksums { + checksums = append(checksums, checksum) + } + + return checksums, nil } // AddChecksum adds a checksum to the list of stored checksums in state. @@ -41,8 +60,13 @@ func AddChecksum(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.Sto } checksums = append(checksums, checksum) - hashes := Checksums{Checksums: checksums} + var hashBz [][]byte + for _, checksum := range checksums { + hashBz = append(hashBz, checksum) + } + + hashes := Checksums{Checksums: hashBz} bz, err := cdc.Marshal(&hashes) if err != nil { return err @@ -72,8 +96,13 @@ func RemoveChecksum(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes. } checksums = slices.DeleteFunc(checksums, func(h Checksum) bool { return bytes.Equal(checksum, h) }) - hashes := Checksums{Checksums: checksums} + var hashBz [][]byte + for _, checksum := range checksums { + hashBz = append(hashBz, checksum) + } + + hashes := Checksums{Checksums: hashBz} bz, err := cdc.Marshal(&hashes) if err != nil { return err diff --git a/modules/light-clients/08-wasm/types/wasm_test.go b/modules/light-clients/08-wasm/types/wasm_test.go index f78dd2d9467..8aac98c9650 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(expectedChecksum[:], checksums[0]) + expectedChecksum, err := types.CreateChecksum(wasmtesting.Code) + suite.Require().NoError(err) + suite.Require().Equal(expectedChecksum, checksums[0]) }, }, {