Skip to content

Commit

Permalink
Add extra required runtime imports for parachain validation
Browse files Browse the repository at this point in the history
This commit adds following import calls:
- ext_default_child_storage_clear_prefix_version_2
- ext_default_child_storage_root_version_2
- ext_offchain_index_clear_version_1
  • Loading branch information
kishansagathiya committed May 11, 2023
1 parent d594e1e commit e963332
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/runtime/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const (
// v0.9 test API wasm
HOST_API_TEST_RUNTIME = "hostapi_runtime"
HOST_API_TEST_RUNTIME_FP = "hostapi_runtime.compact.wasm"
HOST_API_TEST_RUNTIME_URL = "https://github.com/ChainSafe/polkadot-spec/blob/4d190603d21d4431888bcb1ec546c4dc03b7bf93/test/runtimes/hostapi/hostapi_runtime.compact.wasm?raw=true" //nolint:lll
HOST_API_TEST_RUNTIME_URL = "https://raw.githubusercontent.com/ChainSafe/gossamer/kishan/feat/extra-runtime-imports/lib/runtime/wasmer/hostapi_runtime.compact.wasm" //nolint:lll

// v0.9.29 polkadot
POLKADOT_RUNTIME_v0929 = "polkadot_runtime-v929"
Expand Down
1 change: 1 addition & 0 deletions lib/runtime/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Storage interface {
ClearChildStorage(keyToChild, key []byte) error
NextKey([]byte) []byte
ClearPrefixInChild(keyToChild, prefix []byte) error
ClearPrefixInChildWithLimit(keyToChild, prefix []byte, limit uint32) error
GetChildNextKey(keyToChild, key []byte) ([]byte, error)
GetChild(keyToChild []byte) (*trie.Trie, error)
ClearPrefix(prefix []byte) (err error)
Expand Down
20 changes: 20 additions & 0 deletions lib/runtime/storage/trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,26 @@ func (s *TrieState) ClearPrefixInChild(keyToChild, prefix []byte) error {
return nil
}

func (s *TrieState) ClearPrefixInChildWithLimit(keyToChild, prefix []byte, limit uint32) error {
s.lock.Lock()
defer s.lock.Unlock()

child, err := s.t.GetChild(keyToChild)
if err != nil {
return err
}
if child == nil {
return nil
}

_, _, err = child.ClearPrefixLimit(prefix, limit)
if err != nil {
return fmt.Errorf("clearing prefix in child trie located at key 0x%x: %w", keyToChild, err)
}

return nil
}

// GetChildNextKey returns the next lexicographical larger key from child storage. If it does not exist, it returns nil.
func (s *TrieState) GetChildNextKey(keyToChild, key []byte) ([]byte, error) {
s.lock.RLock()
Expand Down
Binary file added lib/runtime/wasmer/hostapi_runtime.compact.wasm
Binary file not shown.
49 changes: 49 additions & 0 deletions lib/runtime/wasmer/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,32 @@ func ext_default_child_storage_clear_prefix_version_1(env interface{}, args []wa
return nil, nil
}

//export ext_default_child_storage_clear_prefix_version_2
func ext_default_child_storage_clear_prefix_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) {
logger.Debug("executing...")

instanceContext := env.(*runtime.Context)
storage := instanceContext.Storage
childStorageKey := args[0].I64()
prefixSpan := args[1].I64()
limitSpan := args[2].I64()

keyToChild := asMemorySlice(instanceContext, childStorageKey)
prefix := asMemorySlice(instanceContext, prefixSpan)

var limit *uint32
err := scale.Unmarshal(asMemorySlice(instanceContext, limitSpan), limit)
if err != nil {
logger.Errorf("failed to decode limit: %s", err)
}

err = storage.ClearPrefixInChildWithLimit(keyToChild, prefix, *limit)
if err != nil {
logger.Errorf("failed to clear prefix in child with limit: %s", err)
}
return []wasmer.Value{wasmer.NewI64(0)}, nil
}

//export ext_default_child_storage_exists_version_1
func ext_default_child_storage_exists_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) {
logger.Debug("executing...")
Expand Down Expand Up @@ -1162,6 +1188,12 @@ func ext_default_child_storage_root_version_1(env interface{}, args []wasmer.Val
return []wasmer.Value{wasmer.NewI64(root)}, nil
}

//export ext_default_child_storage_root_version_2
func ext_default_child_storage_root_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) {
// TODO: Implement this after we have storage trie version 1 implemented #2418
return ext_default_child_storage_root_version_1(env, args)
}

//export ext_default_child_storage_set_version_1
func ext_default_child_storage_set_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) {
logger.Debug("executing...")
Expand Down Expand Up @@ -1570,6 +1602,23 @@ func ext_offchain_index_set_version_1(env interface{}, args []wasmer.Value) ([]w
return nil, nil
}

//export ext_offchain_index_clear_version_1
func ext_offchain_index_clear_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) {
// Remove a key and its associated value from the Offchain DB.
// https://github.com/paritytech/substrate/blob/4d608f9c42e8d70d835a748fa929e59a99497e90/primitives/io/src/lib.rs#L1213
logger.Trace("executing...")
instanceContext := env.(*runtime.Context)
keySpan := args[0].I64()

storageKey := asMemorySlice(instanceContext, keySpan)
err := instanceContext.NodeStorage.BaseDB.Del(storageKey)

if err != nil {
logger.Errorf("failed to set value in raw storage: %s", err)
}
return nil, nil
}

//export ext_offchain_local_storage_clear_version_1
func ext_offchain_local_storage_clear_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) {
logger.Trace("executing...")
Expand Down
18 changes: 18 additions & 0 deletions lib/runtime/wasmer/imports_func.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ func importsNodeRuntime(store *wasmer.Store, memory *wasmer.Memory, ctx *runtime
importsMap["memory"] = memory
}

importsMap["ext_offchain_index_clear_version_1"] = wasmer.NewFunctionWithEnvironment(store,
wasmer.NewFunctionType(
wasmer.NewValueTypes(wasmer.I64),
wasmer.NewValueTypes(),
), ctx, ext_offchain_index_clear_version_1)

importsMap["ext_logging_log_version_1"] = wasmer.NewFunctionWithEnvironment(store,
wasmer.NewFunctionType(
wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64),
Expand Down Expand Up @@ -257,6 +263,12 @@ func importsNodeRuntime(store *wasmer.Store, memory *wasmer.Memory, ctx *runtime
wasmer.NewValueTypes(),
), ctx, ext_default_child_storage_clear_prefix_version_1)

importsMap["ext_default_child_storage_clear_prefix_version_2"] = wasmer.NewFunctionWithEnvironment(store,
wasmer.NewFunctionType(
wasmer.NewValueTypes(wasmer.I64, wasmer.I64, wasmer.I64),
wasmer.NewValueTypes(wasmer.I64),
), ctx, ext_default_child_storage_clear_prefix_version_2)

importsMap["ext_default_child_storage_exists_version_1"] = wasmer.NewFunctionWithEnvironment(store,
wasmer.NewFunctionType(
wasmer.NewValueTypes(wasmer.I64, wasmer.I64),
Expand All @@ -281,6 +293,12 @@ func importsNodeRuntime(store *wasmer.Store, memory *wasmer.Memory, ctx *runtime
wasmer.NewValueTypes(wasmer.I64),
), ctx, ext_default_child_storage_root_version_1)

importsMap["ext_default_child_storage_root_version_2"] = wasmer.NewFunctionWithEnvironment(store,
wasmer.NewFunctionType(
wasmer.NewValueTypes(wasmer.I64, wasmer.I32),
wasmer.NewValueTypes(wasmer.I64),
), ctx, ext_default_child_storage_root_version_2)

importsMap["ext_default_child_storage_set_version_1"] = wasmer.NewFunctionWithEnvironment(store,
wasmer.NewFunctionType(
wasmer.NewValueTypes(wasmer.I64, wasmer.I64, wasmer.I64),
Expand Down
68 changes: 68 additions & 0 deletions lib/runtime/wasmer/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ var testChildKey = []byte("childKey")
var testKey = []byte("key")
var testValue = []byte("value")

func Test_ext_offchain_index_clear_version_1(t *testing.T) {
inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)

testKey := []byte("testkey")
testValue := []byte("testvalue")
err := inst.ctx.NodeStorage.BaseDB.Put(testKey, testValue)
require.NoError(t, err)

encKey, err := scale.Marshal(testKey)
require.NoError(t, err)

_, err = inst.Exec("ext_offchain_index_clear_version_1", encKey)
require.NoError(t, err)

value, err := inst.ctx.NodeStorage.BaseDB.Get(testKey)
require.NoError(t, err)

require.True(t, bytes.Equal(testValue, value))
}

func Test_ext_offchain_timestamp_version_1(t *testing.T) {
inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)
runtimeFunc, err := inst.vm.Exports.GetFunction("rtm_ext_offchain_timestamp_version_1")
Expand Down Expand Up @@ -1289,6 +1309,54 @@ func Test_ext_default_child_storage_clear_prefix_version_1(t *testing.T) {
require.Equal(t, 0, len(keys))
}

func Test_ext_default_child_storage_clear_prefix_version_2(t *testing.T) {
inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)

prefix := []byte("key")
limit := uint32(0)

testKeyValuePair := []struct {
key []byte
value []byte
}{
{[]byte("keyOne"), []byte("value1")},
{[]byte("keyTwo"), []byte("value2")},
{[]byte("keyThree"), []byte("value3")},
}

err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie())
require.NoError(t, err)

for _, kv := range testKeyValuePair {
err = inst.ctx.Storage.SetChildStorage(testChildKey, kv.key, kv.value)
require.NoError(t, err)
}

// Confirm if value is set
keys, err := inst.ctx.Storage.(*storage.TrieState).GetKeysWithPrefixFromChild(testChildKey, prefix)
require.NoError(t, err)
require.Equal(t, 3, len(keys))

encChildKey, err := scale.Marshal(testChildKey)
require.NoError(t, err)

encPrefix, err := scale.Marshal(prefix)
require.NoError(t, err)

encLimit, err := scale.Marshal(limit)
require.NoError(t, err)

data := append(encChildKey, encPrefix...)
data = append(data, encLimit...)

_, err = inst.Exec("rtm_ext_default_child_storage_clear_prefix_version_2", data)
require.NoError(t, err)

keys, err = inst.ctx.Storage.(*storage.TrieState).GetKeysWithPrefixFromChild(testChildKey, prefix)
require.NoError(t, err)
require.Equal(t, 0, len(keys))
}

func Test_ext_default_child_storage_exists_version_1(t *testing.T) {
inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)

Expand Down
1 change: 1 addition & 0 deletions lib/runtime/wasmer/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ func (in *Instance) Exec(function string, data []byte) (result []byte, err error
memory := in.ctx.Memory.Data()
copy(memory[inputPtr:inputPtr+dataLength], data)

fmt.Println("in.vm.Exports", in.vm.Exports)
runtimeFunc, err := in.vm.Exports.GetFunction(function)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrExportFunctionNotFound, function)
Expand Down
1 change: 1 addition & 0 deletions lib/runtime/wasmer/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Storage interface {
ClearChildStorage(keyToChild, key []byte) error
NextKey([]byte) []byte
ClearPrefixInChild(keyToChild, prefix []byte) error
ClearPrefixInChildWithLimit(keyToChild, prefix []byte, limit uint32) error
GetChildNextKey(keyToChild, key []byte) ([]byte, error)
GetChild(keyToChild []byte) (*trie.Trie, error)
ClearPrefix(prefix []byte) (err error)
Expand Down

0 comments on commit e963332

Please sign in to comment.