Skip to content

Commit

Permalink
Implement runtime functions using v1 state trie:
Browse files Browse the repository at this point in the history
- `ext_trie_blake2_256_root_version_2`
- `ext_trie_blake2_256_ordered_root_version_2`
- `ext_trie_blake2_256_verify_proof_version_2`
- `ext_default_child_storage_root_version_2`
- `ext_storage_root_version_2`
  • Loading branch information
qdm12 committed Jul 13, 2022
1 parent 8fd2188 commit 9064e4b
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 11 deletions.
7 changes: 7 additions & 0 deletions lib/runtime/wasmer/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package wasmer

import "fmt"

func panicf(format string, args ...interface{}) {
panic(fmt.Sprintf(format, args...))
}
198 changes: 187 additions & 11 deletions lib/runtime/wasmer/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ package wasmer
// extern void ext_crypto_start_batch_verify_version_1(void *context);
//
// extern int32_t ext_trie_blake2_256_root_version_1(void *context, int64_t a);
// extern int32_t ext_trie_blake2_256_root_version_2(void *context, int64_t data, int32_t version);
// extern int32_t ext_trie_blake2_256_ordered_root_version_1(void *context, int64_t a);
// extern int32_t ext_trie_blake2_256_ordered_root_version_2(void *context, int64_t a, int32_t b);
// extern int32_t ext_trie_blake2_256_ordered_root_version_2(void *context, int64_t data, int32_t version);
// extern int32_t ext_trie_blake2_256_verify_proof_version_1(void *context, int32_t a, int64_t b, int64_t c, int64_t d);
// extern int32_t ext_trie_blake2_256_verify_proof_version_2(void *context, int32_t root, int64_t proof, int64_t key, int64_t value, int32_t version);
//
// extern int64_t ext_misc_runtime_version_version_1(void *context, int64_t a);
// extern void ext_misc_print_hex_version_1(void *context, int64_t a);
Expand All @@ -48,6 +50,7 @@ package wasmer
// extern int64_t ext_default_child_storage_next_key_version_1(void *context, int64_t a, int64_t b);
// extern int64_t ext_default_child_storage_read_version_1(void *context, int64_t a, int64_t b, int64_t c, int32_t d);
// extern int64_t ext_default_child_storage_root_version_1(void *context, int64_t a);
// extern int32_t ext_default_child_storage_root_version_2(void *context, int64_t child_storage_key, int32_t version);
// extern void ext_default_child_storage_set_version_1(void *context, int64_t a, int64_t b, int64_t c);
// extern void ext_default_child_storage_storage_kill_version_1(void *context, int64_t a);
// extern int32_t ext_default_child_storage_storage_kill_version_2(void *context, int64_t a, int64_t b);
Expand Down Expand Up @@ -92,7 +95,7 @@ package wasmer
// extern int64_t ext_storage_read_version_1(void *context, int64_t a, int64_t b, int32_t c);
// extern void ext_storage_rollback_transaction_version_1(void *context);
// extern int64_t ext_storage_root_version_1(void *context);
// extern int64_t ext_storage_root_version_2(void *context, int32_t a);
// extern int32_t ext_storage_root_version_2(void *context, int32_t version);
// extern void ext_storage_set_version_1(void *context, int64_t a, int64_t b);
// extern void ext_storage_start_transaction_version_1(void *context);
//
Expand All @@ -101,6 +104,7 @@ package wasmer
import "C"

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
Expand Down Expand Up @@ -826,6 +830,43 @@ func ext_trie_blake2_256_root_version_1(context unsafe.Pointer, dataSpan C.int64
return C.int32_t(ptr)
}

// https://spec.polkadot.network/#_version_2_prototype_9
//export ext_trie_blake2_256_root_version_2
func ext_trie_blake2_256_root_version_2(context unsafe.Pointer, dataPtrSize C.int64_t,
version C.int32_t) (rootHashPtr C.int32_t) {
instanceContext := wasm.IntoInstanceContext(context)
data := asMemorySlice(instanceContext, dataPtrSize)

var keyValues []struct {
Key []byte
Value []byte
}
if err := scale.Unmarshal(data, &keyValues); err != nil {
panicf("failed scale unmarshaling data: %s", err)
}

versionUint8 := uint8(version)

t := trie.NewEmptyTrie()
for _, keyValue := range keyValues {
t.Put(keyValue.Key, keyValue.Value, versionUint8)
}

rootHash, err := t.Hash(versionUint8)
if err != nil {
panicf("failed to compute root hash: %s", err)
}

const rootHashSize = 32
goRootHashPtr, err := toWasmMemorySized(instanceContext, rootHash[:], rootHashSize)
if err != nil {
panicf("failed to allocate memory for root hash: %s", err)
}

rootHashPtr = C.int32_t(goRootHashPtr)
return rootHashPtr
}

//export ext_trie_blake2_256_ordered_root_version_1
func ext_trie_blake2_256_ordered_root_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t {
logger.Debug("executing...")
Expand Down Expand Up @@ -874,10 +915,45 @@ func ext_trie_blake2_256_ordered_root_version_1(context unsafe.Pointer, dataSpan
return C.int32_t(ptr)
}

// https://spec.polkadot.network/#_version_2_prototype_10
//export ext_trie_blake2_256_ordered_root_version_2
func ext_trie_blake2_256_ordered_root_version_2(context unsafe.Pointer, dataSpan C.int64_t, version C.int32_t) C.int32_t {
// TODO: update to use state trie version 1 (#2418)
return ext_trie_blake2_256_ordered_root_version_1(context, dataSpan)
func ext_trie_blake2_256_ordered_root_version_2(context unsafe.Pointer, dataPtrSize C.int64_t,
version C.int32_t) (result C.int32_t) {
instanceContext := wasm.IntoInstanceContext(context)

var values [][]byte
dataBytes := asMemorySlice(instanceContext, dataPtrSize)
decoder := scale.NewDecoder(bytes.NewBuffer(dataBytes))
err := decoder.Decode(&values)
if err != nil {
panicf("failed to decode scale encoded data: %s", err)
}

versionUint8 := uint8(version)

t := trie.NewEmptyTrie()

for i, value := range values {
key, err := scale.Marshal(uint(i))
if err != nil {
panicf("failed scale encoding value index: %s", err)
}

t.Put(key, value, versionUint8)
}

rootHash, err := t.Hash(versionUint8)
if err != nil {
panicf("failed to compute root hash: %s", err)
}

result, err = rootHashToWasmMemory(instanceContext, rootHash)
if err != nil {
logger.Errorf(err.Error())
return 0
}

return result
}

//export ext_trie_blake2_256_verify_proof_version_1
Expand Down Expand Up @@ -909,6 +985,37 @@ func ext_trie_blake2_256_verify_proof_version_1(context unsafe.Pointer, rootSpan
return C.int32_t(1)
}

// https://spec.polkadot.network/#_version_2_prototype_13
//export ext_trie_blake2_256_verify_proof_version_2
func ext_trie_blake2_256_verify_proof_version_2(context unsafe.Pointer,
rootPtr C.int32_t, proofPtrSize, keyPtrSize, valuePtrSize C.int64_t,
version C.int32_t) (result C.int32_t) {
instanceContext := wasm.IntoInstanceContext(context)
memory := instanceContext.Memory().Data()

proofBytes := getBytes(memory, proofPtrSize)
decoder := scale.NewDecoder(bytes.NewBuffer(proofBytes))
var encodedProofNodes [][]byte
err := decoder.Decode(&encodedProofNodes)
if err != nil {
logger.Errorf("failed scale decoding proof data: %s", err)
return 0
}

rootHash := getRootHash(memory, rootPtr)
keyBytes := getBytes(memory, keyPtrSize)
valueBytes := getBytes(memory, valuePtrSize)
versionUint8 := uint8(version)

err = proof.Verify(encodedProofNodes, rootHash, keyBytes, valueBytes, versionUint8)
if err != nil {
logger.Warnf("failed to verify proof: %s", err)
return 0
}

return 1
}

//export ext_misc_print_hex_version_1
func ext_misc_print_hex_version_1(context unsafe.Pointer, dataSpan C.int64_t) {
logger.Trace("executing...")
Expand Down Expand Up @@ -1129,6 +1236,35 @@ func ext_default_child_storage_root_version_1(context unsafe.Pointer, childStora
return C.int64_t(root)
}

// https://spec.polkadot.network/#_version_2_prototype_4
//export ext_default_child_storage_root_version_2
func ext_default_child_storage_root_version_2(context unsafe.Pointer,
childStorageKeyPtrSize C.int64_t, versionPtr C.int32_t) (resultPtr C.int32_t) {
instanceContext := wasm.IntoInstanceContext(context)
memory := instanceContext.Memory().Data()
storage := instanceContext.Data().(*runtime.Context).Storage

keyToChild := getBytes(memory, childStorageKeyPtrSize)

child, err := storage.GetChild(keyToChild)
if err != nil {
panicf("failed to retrieve child: %s", err)
}

versionUint8 := uint8(versionPtr)
childRootHash, err := child.Hash(versionUint8)
if err != nil {
panicf("failed to encode child root: %s", err)
}

resultPtr, err = rootHashToWasmMemory(instanceContext, childRootHash)
if err != nil {
panic(err)
}

return resultPtr
}

//export ext_default_child_storage_set_version_1
func ext_default_child_storage_set_version_1(context unsafe.Pointer, childStorageKeySpan, keySpan, valueSpan C.int64_t) {
logger.Debug("executing...")
Expand Down Expand Up @@ -2057,10 +2193,25 @@ func ext_storage_root_version_1(context unsafe.Pointer) C.int64_t {
return C.int64_t(rootSpan)
}

// https://spec.polkadot.network/#sect-ext-storage-root-version-2
//export ext_storage_root_version_2
func ext_storage_root_version_2(context unsafe.Pointer, version C.int32_t) C.int64_t {
// TODO: update to use state trie version 1 (#2418)
return ext_storage_root_version_1(context)
func ext_storage_root_version_2(context unsafe.Pointer, version C.int32_t) C.int32_t {
instanceContext := wasm.IntoInstanceContext(context)
storage := instanceContext.Data().(*runtime.Context).Storage

versionUint8 := uint8(version)

rootHash, err := storage.Root(versionUint8)
if err != nil {
panicf("failed to get storage root: %s", err)
}

result, err := rootHashToWasmMemory(instanceContext, rootHash)
if err != nil {
panic(err)
}

return result
}

//export ext_storage_set_version_1
Expand Down Expand Up @@ -2107,10 +2258,32 @@ func ext_storage_commit_transaction_version_1(context unsafe.Pointer) {
// Convert 64bit wasm span descriptor to Go memory slice
func asMemorySlice(context wasm.InstanceContext, span C.int64_t) []byte {
memory := context.Memory().Data()
ptr, size := runtime.Int64ToPointerAndSize(int64(span))
return getBytes(memory, span)
}

func getBytes(memory []byte, ptrSize C.int64_t) []byte {
ptr, size := int32(ptrSize), int32(ptrSize>>32)
return memory[ptr : ptr+size]
}

func getRootHash(memory []byte, ptr C.int32_t) (rootHash []byte) {
const size = 32
return memory[ptr : ptr+size]
}

func rootHashToWasmMemory(context wasm.InstanceContext, rootHash common.Hash) (
ptr C.int32_t, err error) {
const size = 32

goPtr, err := toWasmMemorySized(context, rootHash[:], size)
if err != nil {
return 0, err
}

ptr = C.int32_t(goPtr)
return ptr, nil
}

// Copy a byte slice to wasm memory and return the resulting 64bit span descriptor
func toWasmMemory(context wasm.InstanceContext, data []byte) (int64, error) {
allocator := context.Data().(*runtime.Context).Allocator
Expand All @@ -2134,14 +2307,14 @@ func toWasmMemory(context wasm.InstanceContext, data []byte) (int64, error) {
// Copy a byte slice of a fixed size to wasm memory and return resulting pointer
func toWasmMemorySized(context wasm.InstanceContext, data []byte, size uint32) (uint32, error) {
if int(size) != len(data) {
return 0, errors.New("internal byte array size missmatch")
return 0, errors.New("internal byte array size mismatch")
}

allocator := context.Data().(*runtime.Context).Allocator

out, err := allocator.Allocate(size)
if err != nil {
return 0, err
return 0, fmt.Errorf("allocating memory: %w", err)
}

memory := context.Memory().Data()
Expand Down Expand Up @@ -2264,6 +2437,7 @@ func ImportsNodeRuntime() (imports *wasm.Imports, err error) {
{"ext_default_child_storage_next_key_version_1", ext_default_child_storage_next_key_version_1, C.ext_default_child_storage_next_key_version_1},
{"ext_default_child_storage_read_version_1", ext_default_child_storage_read_version_1, C.ext_default_child_storage_read_version_1},
{"ext_default_child_storage_root_version_1", ext_default_child_storage_root_version_1, C.ext_default_child_storage_root_version_1},
{"ext_default_child_storage_root_version_2", ext_default_child_storage_root_version_2, C.ext_default_child_storage_root_version_2},
{"ext_default_child_storage_set_version_1", ext_default_child_storage_set_version_1, C.ext_default_child_storage_set_version_1},
{"ext_default_child_storage_storage_kill_version_1", ext_default_child_storage_storage_kill_version_1, C.ext_default_child_storage_storage_kill_version_1},
{"ext_default_child_storage_storage_kill_version_2", ext_default_child_storage_storage_kill_version_2, C.ext_default_child_storage_storage_kill_version_2},
Expand Down Expand Up @@ -2321,7 +2495,9 @@ func ImportsNodeRuntime() (imports *wasm.Imports, err error) {
{"ext_trie_blake2_256_ordered_root_version_1", ext_trie_blake2_256_ordered_root_version_1, C.ext_trie_blake2_256_ordered_root_version_1},
{"ext_trie_blake2_256_ordered_root_version_2", ext_trie_blake2_256_ordered_root_version_2, C.ext_trie_blake2_256_ordered_root_version_2},
{"ext_trie_blake2_256_root_version_1", ext_trie_blake2_256_root_version_1, C.ext_trie_blake2_256_root_version_1},
{"ext_trie_blake2_256_root_version_2", ext_trie_blake2_256_root_version_2, C.ext_trie_blake2_256_root_version_2},
{"ext_trie_blake2_256_verify_proof_version_1", ext_trie_blake2_256_verify_proof_version_1, C.ext_trie_blake2_256_verify_proof_version_1},
{"ext_trie_blake2_256_verify_proof_version_2", ext_trie_blake2_256_verify_proof_version_2, C.ext_trie_blake2_256_verify_proof_version_2},
} {
_, err = imports.AppendFunction(toRegister.importName, toRegister.implementation, toRegister.cgoPointer)
if err != nil {
Expand Down

0 comments on commit 9064e4b

Please sign in to comment.