Skip to content

Commit

Permalink
chore: address vanity nits in 08-wasm (code structure, godocs) (cosmo…
Browse files Browse the repository at this point in the history
…s#5320)

* chore: restructure mock_engine.go

* chore: consolidate sdk.Msg codec registration

* chore: adding godoc to WasmConfig

* chore: move state storage code to store.go, rm ambiguous wasm.go and wasm_test.go files

* chore: add more meat to mock engine godoc

* chore: update storeAdapter godoc to use wasmvmtypes.KVStore

* lint: yes

* Update modules/light-clients/08-wasm/testing/mock_engine.go
  • Loading branch information
damiannolan committed Dec 6, 2023
1 parent 0b40489 commit cb74fd1
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 204 deletions.
45 changes: 25 additions & 20 deletions modules/light-clients/08-wasm/testing/mock_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,31 @@ type (
sudoFn func(checksum 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)
)

// MockWasmEngine implements types.WasmEngine for testing purposes. One or multiple messages can be stubbed.
// Without a stub function a panic is thrown.
// ref: https://github.com/CosmWasm/wasmd/blob/v0.42.0/x/wasm/keeper/wasmtesting/mock_engine.go#L19
type MockWasmEngine struct {
StoreCodeFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error)
StoreCodeUncheckedFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error)
InstantiateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error)
MigrateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error)
GetCodeFn func(checksum wasmvm.Checksum) (wasmvm.WasmCode, error)
PinFn func(checksum wasmvm.Checksum) error
UnpinFn func(checksum wasmvm.Checksum) error

// queryCallbacks contains a mapping of queryMsg field type name to callback function.
queryCallbacks map[string]queryFn
sudoCallbacks map[string]sudoFn

// contracts contains a mapping of checksum to code.
storedContracts map[uint32][]byte
}

// NewMockWasmEngine creates and returns a new instance of the mock wasmvm for testing purposes.
// Each callback method of the mock wasmvm can be overridden to assign specific functionality.
// Default functionality is assigned for StoreCode, StoreCodeUnchecked and GetCode. Both Pin and Unpin are implemented as no-op methods.
// All other callbacks stored in the query and sudo callback maps panic. Use RegisterQueryCallback and RegisterSudoCallback methods
// to assign expected behaviour for test cases.
func NewMockWasmEngine() *MockWasmEngine {
m := &MockWasmEngine{
queryCallbacks: map[string]queryFn{},
Expand Down Expand Up @@ -107,26 +132,6 @@ func (m *MockWasmEngine) RegisterSudoCallback(sudoMessage any, fn sudoFn) {
m.sudoCallbacks[typeName] = fn
}

// MockWasmEngine implements types.WasmEngine for testing purpose. One or multiple messages can be stubbed.
// Without a stub function a panic is thrown.
// ref: https://github.com/CosmWasm/wasmd/blob/v0.42.0/x/wasm/keeper/wasmtesting/mock_engine.go#L19
type MockWasmEngine struct {
StoreCodeFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error)
StoreCodeUncheckedFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error)
InstantiateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error)
MigrateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error)
GetCodeFn func(checksum wasmvm.Checksum) (wasmvm.WasmCode, error)
PinFn func(checksum wasmvm.Checksum) error
UnpinFn func(checksum wasmvm.Checksum) error

// queryCallbacks contains a mapping of queryMsg field type name to callback function.
queryCallbacks map[string]queryFn
sudoCallbacks map[string]sudoFn

// contracts contains a mapping of checksum to code.
storedContracts map[uint32][]byte
}

// StoreCode implements the WasmEngine interface.
func (m *MockWasmEngine) StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) {
if m.StoreCodeFn == nil {
Expand Down
6 changes: 0 additions & 6 deletions modules/light-clients/08-wasm/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgStoreCode{},
)
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgMigrateContract{},
)
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgRemoveChecksum{},
)

Expand Down
3 changes: 3 additions & 0 deletions modules/light-clients/08-wasm/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const (
defaultContractDebugMode = false
)

// WasmConfig defines configuration parameters for the 08-wasm wasm virtual machine instance.
// It includes the `dataDir` intended to be used for wasm blobs and internal caches, as well as a comma separated list
// of features or capabilities the user wishes to enable. A boolean flag is provided to enable debug mode.
type WasmConfig struct {
// DataDir is the directory for Wasm blobs and various caches
DataDir string
Expand Down
53 changes: 53 additions & 0 deletions modules/light-clients/08-wasm/types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ package types

import (
"bytes"
"context"
"errors"
"io"
"reflect"
"strings"

wasmvm "github.com/CosmWasm/wasmvm"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"

errorsmod "cosmossdk.io/errors"
"cosmossdk.io/store/cachekv"
storeprefix "cosmossdk.io/store/prefix"
"cosmossdk.io/store/tracekv"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm"
)

var (
Expand All @@ -24,6 +28,50 @@ var (
substitutePrefix = []byte("substitute/")
)

// Checksum is a type alias used for wasm byte code checksums.
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
func GetAllChecksums(ctx context.Context) ([]Checksum, error) {
iterator, err := ibcwasm.Checksums.Iterate(ctx, nil)
if err != nil {
return nil, err
}

keys, err := iterator.Keys()
if err != nil {
return nil, err
}

checksums := []Checksum{}
for _, key := range keys {
checksums = append(checksums, key)
}

return checksums, nil
}

// HasChecksum returns true if the given checksum exists in the store and
// false otherwise.
func HasChecksum(ctx context.Context, checksum Checksum) bool {
found, err := ibcwasm.Checksums.Has(ctx, checksum)
if err != nil {
return false
}

return found
}

// migrateClientWrappedStore combines two KVStores into one.
//
// Both stores are used for reads, but only the subjectStore is used for writes. For all operations, the key
Expand Down Expand Up @@ -205,22 +253,27 @@ func newStoreAdapter(s storetypes.KVStore) *storeAdapter {
return &storeAdapter{parent: s}
}

// Get implements the wasmvmtypes.KVStore interface.
func (s storeAdapter) Get(key []byte) []byte {
return s.parent.Get(key)
}

// Set implements the wasmvmtypes.KVStore interface.
func (s storeAdapter) Set(key, value []byte) {
s.parent.Set(key, value)
}

// Delete implements the wasmvmtypes.KVStore interface.
func (s storeAdapter) Delete(key []byte) {
s.parent.Delete(key)
}

// Iterator implements the wasmvmtypes.KVStore interface.
func (s storeAdapter) Iterator(start, end []byte) wasmvmtypes.Iterator {
return s.parent.Iterator(start, end)
}

// ReverseIterator implements the wasmvmtypes.KVStore interface.
func (s storeAdapter) ReverseIterator(start, end []byte) wasmvmtypes.Iterator {
return s.parent.ReverseIterator(start, end)
}
Expand Down
118 changes: 118 additions & 0 deletions modules/light-clients/08-wasm/types/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,131 @@ import (
prefixstore "cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/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"
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
)

var invalidPrefix = []byte("invalid/")

func (suite *TypesTestSuite) TestGetChecksums() {
testCases := []struct {
name string
malleate func()
expResult func(checksums []types.Checksum)
}{
{
"success: no contract stored.",
func() {},
func(checksums []types.Checksum) {
suite.Require().Len(checksums, 0)
},
},
{
"success: default mock vm contract stored.",
func() {
suite.SetupWasmWithMockVM()
},
func(checksums []types.Checksum) {
suite.Require().Len(checksums, 1)
expectedChecksum, err := types.CreateChecksum(wasmtesting.Code)
suite.Require().NoError(err)
suite.Require().Equal(expectedChecksum, checksums[0])
},
},
{
"success: non-empty checksums",
func() {
suite.SetupWasmWithMockVM()

err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), types.Checksum("checksum"))
suite.Require().NoError(err)
},
func(checksums []types.Checksum) {
suite.Require().Len(checksums, 2)
suite.Require().Contains(checksums, types.Checksum("checksum"))
},
},
}

for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
tc.malleate()

checksums, err := types.GetAllChecksums(suite.chainA.GetContext())
suite.Require().NoError(err)
tc.expResult(checksums)
})
}
}

func (suite *TypesTestSuite) TestAddChecksum() {
suite.SetupWasmWithMockVM()

checksums, err := types.GetAllChecksums(suite.chainA.GetContext())
suite.Require().NoError(err)
// default mock vm contract is stored
suite.Require().Len(checksums, 1)

checksum1 := types.Checksum("checksum1")
checksum2 := types.Checksum("checksum2")
err = ibcwasm.Checksums.Set(suite.chainA.GetContext(), checksum1)
suite.Require().NoError(err)
err = ibcwasm.Checksums.Set(suite.chainA.GetContext(), checksum2)
suite.Require().NoError(err)

// Test adding the same checksum twice
err = ibcwasm.Checksums.Set(suite.chainA.GetContext(), checksum1)
suite.Require().NoError(err)

checksums, err = types.GetAllChecksums(suite.chainA.GetContext())
suite.Require().NoError(err)
suite.Require().Len(checksums, 3)
suite.Require().Contains(checksums, checksum1)
suite.Require().Contains(checksums, checksum2)
}

func (suite *TypesTestSuite) TestHasChecksum() {
var checksum types.Checksum

testCases := []struct {
name string
malleate func()
exprResult bool
}{
{
"success: checksum exists",
func() {
checksum = types.Checksum("checksum")
err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), checksum)
suite.Require().NoError(err)
},
true,
},
{
"success: checksum does not exist",
func() {
checksum = types.Checksum("non-existent-checksum")
},
false,
},
}

for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupWasmWithMockVM()

tc.malleate()

result := types.HasChecksum(suite.chainA.GetContext(), checksum)
suite.Require().Equal(tc.exprResult, result)
})
}
}

// TestMigrateClientWrappedStoreGetStore tests the getStore method of the migrateClientWrappedStore.
func (suite *TypesTestSuite) TestMigrateClientWrappedStoreGetStore() {
// calls suite.SetupWasmWithMockVM() and creates two clients with their respective stores
Expand Down
54 changes: 0 additions & 54 deletions modules/light-clients/08-wasm/types/wasm.go

This file was deleted.

Loading

0 comments on commit cb74fd1

Please sign in to comment.