Skip to content

Commit

Permalink
Add testing for Wasm implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
0xalank committed Oct 2, 2023
1 parent 522f383 commit 93bd746
Show file tree
Hide file tree
Showing 18 changed files with 3,308 additions and 0 deletions.
71 changes: 71 additions & 0 deletions core/vm/logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package vm

import (
"math/big"

"github.com/dominant-strategies/go-quai/common"
"github.com/dominant-strategies/go-quai/core/state"
)

type dummyContractRef struct {
calledForEach bool
}

func (dummyContractRef) Address() common.Address { return common.Address{} }
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
func (dummyContractRef) SetCode(common.Hash, []byte) {}
func (d *dummyContractRef) ForEachStorage(callback func(key, value common.Hash) bool) {
d.calledForEach = true
}
func (d *dummyContractRef) SubBalance(amount *big.Int) {}
func (d *dummyContractRef) AddBalance(amount *big.Int) {}
func (d *dummyContractRef) SetBalance(*big.Int) {}
func (d *dummyContractRef) SetNonce(uint64) {}
func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) }

type dummyStatedb struct {
state.StateDB
}

func (*dummyStatedb) GetRefund() uint64 { return 1337 }

// func TestStoreCapture(t *testing.T) {
// var (
// env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
// logger = NewStructLogger(nil)
// contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
// scope = &ScopeContext{
// Memory: NewMemory(),
// Stack: newstack(),
// Contract: contract,
// }
// )
// scope.Stack.push(uint256.NewInt(1))
// scope.Stack.push(new(uint256.Int))
// var index common.Hash
// logger.CaptureState(env, 0, SSTORE, 0, 0, scope, nil, 0, nil)
// if len(logger.storage[contract.Address()]) == 0 {
// t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(),
// len(logger.storage[contract.Address()]))
// }
// exp := common.BigToHash(big.NewInt(1))
// if logger.storage[contract.Address()][index] != exp {
// t.Errorf("expected %x, got %x", exp, logger.storage[contract.Address()][index])
// }
// }
2 changes: 2 additions & 0 deletions core/vm/wasm_contracts/get_address/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
tinygo build -o get_address.wasm -scheduler=none --no-debug -target wasi ./get_address.go
82 changes: 82 additions & 0 deletions core/vm/wasm_contracts/get_address/get_address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

// import "unsafe"

// // main is required for TinyGo to compile to Wasm.
// func main() {}

// //export run
// //go:linkname run
// func run() {
// var address [8]uint32
// rawAddress := uintptr(unsafe.Pointer(&address[0]))
// int32Address := (*int32)(unsafe.Pointer(rawAddress))
// getAddress(int32Address)
// }

// //export getAddress
// //go:linkname getAddress
// func getAddress(resultOffset int32)

/*
#include <stdint.h>
extern void getAddress(uint32_t *offset);
extern void storageStore(uint32_t *keyOffset, uint32_t *valueOffset);
*/
import (
"reflect"
"strconv"
"unsafe"
)

func main() {}

//export hostLogString
//go:linkname hostLogString
func hostLogString(offset uint32, byteCount uint32)

//export run
//go:linkname run
func run() {
var address string
rawAddress := uintptr(unsafe.Pointer(&address))

int32RawAddress := int32(int64(rawAddress))

getAddress(int32RawAddress)

addressString := ptrToString(uint32(rawAddress), 42)

hostLogString(strToPtr(addressString))
hostLogString(strToPtr("pointer " + strconv.Itoa(int(int32RawAddress))))
hostLogString(strToPtr("Hello from wasm"))

}

//export getAddress
//go:linkname getAddress
func getAddress(resultOffset int32)


// ptrToString returns a string from WebAssembly compatible numeric types
// representing its pointer and length.
func ptrToString(ptr uint32, size uint32) string {
// Get a slice view of the underlying bytes in the stream. We use SliceHeader, not StringHeader
// as it allows us to fix the capacity to what was allocated.
return *(*string)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(ptr),
Len: uintptr(size), // Tinygo requires these as uintptrs even if they are int fields.
Cap: uintptr(size), // ^^ See https://github.com/tinygo-org/tinygo/issues/1284
}))
}


// strToPtr returns a pointer and size pair for the given string in a way
// compatible with WebAssembly numeric types.
func strToPtr(s string) (uint32, uint32) {
buf := []byte(s)
ptr := &buf[0]
unsafePtr := uintptr(unsafe.Pointer(ptr))
return uint32(unsafePtr), uint32(len(buf))
}
Binary file not shown.
2 changes: 2 additions & 0 deletions core/vm/wasm_contracts/get_block_number/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
tinygo build -o get_block_number.wasm -scheduler=none --no-debug -target wasi ./get_block_number.go
33 changes: 33 additions & 0 deletions core/vm/wasm_contracts/get_block_number/get_block_number.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"strconv"
"unsafe"
)

// main is required for TinyGo to compile to Wasm.
func main() {}

//export hostLogString
//go:linkname hostLogString
func hostLogString(offset uint32, byteCount uint32)

//export run
//go:linkname run
func run() {
number := getBlockNumber()
hostLogString(strToPtr(strconv.Itoa(int(number))))
}

//export getBlockNumber
//go:linkname getBlockNumber
func getBlockNumber() int64

// strToPtr returns a pointer and size pair for the given string in a way
// compatible with WebAssembly numeric types.
func strToPtr(s string) (uint32, uint32) {
buf := []byte(s)
ptr := &buf[0]
unsafePtr := uintptr(unsafe.Pointer(ptr))
return uint32(unsafePtr), uint32(len(buf))
}
Binary file not shown.
2 changes: 2 additions & 0 deletions core/vm/wasm_contracts/get_caller/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
tinygo build -o get_caller.wasm -scheduler=none --no-debug -target wasi ./get_caller.go
81 changes: 81 additions & 0 deletions core/vm/wasm_contracts/get_caller/get_caller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

// import "unsafe"

// // main is required for TinyGo to compile to Wasm.
// func main() {}

// //export run
// //go:linkname run
// func run() {
// var address [8]uint32
// rawAddress := uintptr(unsafe.Pointer(&address[0]))
// int32Address := (*int32)(unsafe.Pointer(rawAddress))
// getAddress(int32Address)
// }

// //export getAddress
// //go:linkname getAddress
// func getAddress(resultOffset int32)

/*
#include <stdint.h>
extern void getAddress(uint32_t *offset);
extern void storageStore(uint32_t *keyOffset, uint32_t *valueOffset);
*/
import (
"reflect"
"strconv"
"unsafe"
)

func main() {}

//export hostLogString
//go:linkname hostLogString
func hostLogString(offset uint32, byteCount uint32)

//export run
//go:linkname run
func run() {
var address string
rawAddress := uintptr(unsafe.Pointer(&address))

int32RawAddress := int32(int64(rawAddress))

getCaller(int32RawAddress)

addressString := ptrToString(uint32(rawAddress), 42)

hostLogString(strToPtr(addressString))
hostLogString(strToPtr("pointer " + strconv.Itoa(int(int32RawAddress))))
hostLogString(strToPtr("Hello from wasm"))
}

//export getCaller
//go:linkname getCaller
func getCaller(resultOffset int32)


// ptrToString returns a string from WebAssembly compatible numeric types
// representing its pointer and length.
func ptrToString(ptr uint32, size uint32) string {
// Get a slice view of the underlying bytes in the stream. We use SliceHeader, not StringHeader
// as it allows us to fix the capacity to what was allocated.
return *(*string)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(ptr),
Len: uintptr(size), // Tinygo requires these as uintptrs even if they are int fields.
Cap: uintptr(size), // ^^ See https://github.com/tinygo-org/tinygo/issues/1284
}))
}


// strToPtr returns a pointer and size pair for the given string in a way
// compatible with WebAssembly numeric types.
func strToPtr(s string) (uint32, uint32) {
buf := []byte(s)
ptr := &buf[0]
unsafePtr := uintptr(unsafe.Pointer(ptr))
return uint32(unsafePtr), uint32(len(buf))
}
Binary file added core/vm/wasm_contracts/get_caller/get_caller.wasm
Binary file not shown.
Loading

0 comments on commit 93bd746

Please sign in to comment.