mukan-ibc/modules/light-clients/08-wasm/keeper/msg_server_test.go
Mukan Erkin Törük 6852832fe8
Some checks failed
CodeQL / Analyze (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Deploy to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled
Buf-Push / push (push) Has been cancelled
initial: sovereign Mukan Network fork
2026-05-11 03:18:28 +03:00

429 lines
12 KiB
Go

package keeper_test
import (
"encoding/hex"
"encoding/json"
"errors"
wasmvm "github.com/CosmWasm/wasmvm/v2"
wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/v10/testing"
"github.com/cosmos/ibc-go/modules/light-clients/08-wasm/v10/types"
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
host "github.com/cosmos/ibc-go/v10/modules/core/24-host"
ibcerrors "github.com/cosmos/ibc-go/v10/modules/core/errors"
ibctesting "github.com/cosmos/ibc-go/v10/testing"
)
func (suite *KeeperTestSuite) TestMsgStoreCode() {
var (
msg *types.MsgStoreCode
signer string
data []byte
)
testCases := []struct {
name string
malleate func()
expError error
}{
{
"success",
func() {
msg = types.NewMsgStoreCode(signer, data)
},
nil,
},
{
"fails with duplicate wasm code",
func() {
msg = types.NewMsgStoreCode(signer, data)
_, err := GetSimApp(suite.chainA).WasmClientKeeper.StoreCode(suite.chainA.GetContext(), msg)
suite.Require().NoError(err)
},
types.ErrWasmCodeExists,
},
{
"fails with zero-length wasm code",
func() {
msg = types.NewMsgStoreCode(signer, []byte{})
},
types.ErrWasmEmptyCode,
},
{
"fails with checksum",
func() {
msg = types.NewMsgStoreCode(signer, []byte{0, 1, 3, 4})
},
errors.New("Wasm bytes do not start with Wasm magic number"),
},
{
"fails with wasm code too large",
func() {
msg = types.NewMsgStoreCode(signer, wasmtesting.CreateMockContract([]byte(ibctesting.GenerateString(uint(types.MaxWasmSize)))))
},
types.ErrWasmCodeTooLarge,
},
{
"fails with unauthorized signer",
func() {
signer = suite.chainA.SenderAccount.GetAddress().String()
msg = types.NewMsgStoreCode(signer, data)
},
ibcerrors.ErrUnauthorized,
},
{
"failure: checksum could not be pinned",
func() {
msg = types.NewMsgStoreCode(signer, data)
suite.mockVM.PinFn = func(_ wasmvm.Checksum) error {
return wasmtesting.ErrMockVM
}
},
wasmtesting.ErrMockVM,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupWasmWithMockVM()
signer = authtypes.NewModuleAddress(govtypes.ModuleName).String()
data = wasmtesting.Code
tc.malleate()
ctx := suite.chainA.GetContext()
res, err := GetSimApp(suite.chainA).WasmClientKeeper.StoreCode(ctx, msg)
events := ctx.EventManager().Events()
if tc.expError == nil {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().NotEmpty(res.Checksum)
// Verify events
expectedEvents := sdk.Events{
sdk.NewEvent(
"store_wasm_code",
sdk.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(res.Checksum)),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
}
for _, evt := range expectedEvents {
suite.Require().Contains(events, evt)
}
} else {
suite.Require().Contains(err.Error(), tc.expError.Error())
suite.Require().Nil(res)
suite.Require().Empty(events)
}
})
}
}
func (suite *KeeperTestSuite) TestMsgMigrateContract() {
oldChecksum, err := types.CreateChecksum(wasmtesting.Code)
suite.Require().NoError(err)
newByteCode := wasmtesting.CreateMockContract([]byte("MockByteCode-TestMsgMigrateContract"))
govAcc := authtypes.NewModuleAddress(govtypes.ModuleName).String()
var (
newChecksum []byte
msg *types.MsgMigrateContract
expClientState *types.ClientState
)
testCases := []struct {
name string
malleate func()
expError error
}{
{
"success: no update to client state",
func() {
msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}"))
suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
data, err := json.Marshal(types.EmptyResult{})
suite.Require().NoError(err)
return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil
}
},
nil,
},
{
"success: update client state",
func() {
msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}"))
suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
// the checksum written in the client state will later be overwritten by the message server.
expClientStateBz := wasmtesting.CreateMockClientStateBz(suite.chainA.App.AppCodec(), []byte("invalid checksum"))
var ok bool
expClientState, ok = clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), expClientStateBz).(*types.ClientState)
suite.Require().True(ok)
store.Set(host.ClientStateKey(), expClientStateBz)
data, err := json.Marshal(types.EmptyResult{})
suite.Require().NoError(err)
return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil
}
},
nil,
},
{
"failure: same checksum",
func() {
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.ContractResult, uint64, error) {
panic("unreachable")
}
},
types.ErrWasmCodeExists,
},
{
"failure: unauthorized signer",
func() {
msg = types.NewMsgMigrateContract(suite.chainA.SenderAccount.GetAddress().String(), defaultWasmClientID, newChecksum, []byte("{}"))
},
ibcerrors.ErrUnauthorized,
},
{
"failure: invalid wasm checksum",
func() {
msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, []byte(ibctesting.InvalidID), []byte("{}"))
},
types.ErrWasmChecksumNotFound,
},
{
"failure: invalid client id",
func() {
msg = types.NewMsgMigrateContract(govAcc, ibctesting.InvalidID, newChecksum, []byte("{}"))
},
clienttypes.ErrClientNotFound,
},
{
"failure: vm returns error",
func() {
msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}"))
suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM
}
},
types.ErrVMError,
},
{
"failure: contract returns error",
func() {
msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}"))
suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil
}
},
types.ErrWasmContractCallFailed,
},
{
"failure: incorrect state update",
func() {
msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}"))
suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
// the checksum written in here will be overwritten
store.Set(host.ClientStateKey(), []byte("changed client state"))
data, err := json.Marshal(types.EmptyResult{})
suite.Require().NoError(err)
return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil
}
},
types.ErrWasmInvalidContractModification,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
var ok bool
suite.SetupWasmWithMockVM()
_ = suite.storeWasmCode(wasmtesting.Code)
newChecksum = suite.storeWasmCode(newByteCode)
endpoint := wasmtesting.NewWasmEndpoint(suite.chainA)
err := endpoint.CreateClient()
suite.Require().NoError(err)
// this is the old client state
expClientState, ok = endpoint.GetClientState().(*types.ClientState)
suite.Require().True(ok)
tc.malleate()
ctx := suite.chainA.GetContext()
res, err := GetSimApp(suite.chainA).WasmClientKeeper.MigrateContract(ctx, msg)
events := ctx.EventManager().Events().ToABCIEvents()
if tc.expError == nil {
expClientState.Checksum = newChecksum
suite.Require().NoError(err)
suite.Require().NotNil(res)
// updated client state
clientState, ok := endpoint.GetClientState().(*types.ClientState)
suite.Require().True(ok)
suite.Require().Equal(expClientState, clientState)
// Verify events
expectedEvents := sdk.Events{
sdk.NewEvent(
"migrate_contract",
sdk.NewAttribute(types.AttributeKeyClientID, defaultWasmClientID),
sdk.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(oldChecksum)),
sdk.NewAttribute(types.AttributeKeyNewChecksum, hex.EncodeToString(newChecksum)),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
}.ToABCIEvents()
for _, evt := range expectedEvents {
suite.Require().Contains(events, evt)
}
} else {
suite.Require().ErrorIs(err, tc.expError)
suite.Require().Nil(res)
}
})
}
}
func (suite *KeeperTestSuite) TestMsgRemoveChecksum() {
checksum, err := types.CreateChecksum(wasmtesting.Code)
suite.Require().NoError(err)
govAcc := authtypes.NewModuleAddress(govtypes.ModuleName).String()
var (
msg *types.MsgRemoveChecksum
expChecksums []types.Checksum
)
testCases := []struct {
name string
malleate func()
expError error
}{
{
"success",
func() {
msg = types.NewMsgRemoveChecksum(govAcc, checksum)
expChecksums = []types.Checksum{}
},
nil,
},
{
"success: many checksums",
func() {
msg = types.NewMsgRemoveChecksum(govAcc, checksum)
expChecksums = []types.Checksum{}
for i := range 20 {
mockCode := wasmtesting.CreateMockContract([]byte{byte(i)})
checksum, err := types.CreateChecksum(mockCode)
suite.Require().NoError(err)
keeper := GetSimApp(suite.chainA).WasmClientKeeper
err = keeper.GetChecksums().Set(suite.chainA.GetContext(), checksum)
suite.Require().NoError(err)
expChecksums = append(expChecksums, checksum)
}
},
nil,
},
{
"failure: checksum is missing",
func() {
msg = types.NewMsgRemoveChecksum(govAcc, []byte{1})
},
types.ErrWasmChecksumNotFound,
},
{
"failure: unauthorized signer",
func() {
msg = types.NewMsgRemoveChecksum(suite.chainA.SenderAccount.GetAddress().String(), checksum)
},
ibcerrors.ErrUnauthorized,
},
{
"failure: code has could not be unpinned",
func() {
msg = types.NewMsgRemoveChecksum(govAcc, checksum)
suite.mockVM.UnpinFn = func(_ wasmvm.Checksum) error {
return wasmtesting.ErrMockVM
}
},
wasmtesting.ErrMockVM,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupWasmWithMockVM()
_ = suite.storeWasmCode(wasmtesting.Code)
endpoint := wasmtesting.NewWasmEndpoint(suite.chainA)
err := endpoint.CreateClient()
suite.Require().NoError(err)
tc.malleate()
ctx := suite.chainA.GetContext()
res, err := GetSimApp(suite.chainA).WasmClientKeeper.RemoveChecksum(ctx, msg)
events := ctx.EventManager().Events().ToABCIEvents()
if tc.expError == nil {
suite.Require().NoError(err)
suite.Require().NotNil(res)
checksums, err := GetSimApp(suite.chainA).WasmClientKeeper.GetAllChecksums(suite.chainA.GetContext())
suite.Require().NoError(err)
// Check equality of checksums up to order
suite.Require().ElementsMatch(expChecksums, checksums)
// Verify events
suite.Require().Len(events, 0)
} else {
suite.Require().ErrorIs(err, tc.expError)
suite.Require().Nil(res)
}
})
}
}