4cf69d7cd3
The tests now compile and won't panic for unexpected return values. We need a recent-enough version of the mutan compiler because of the new JUMPDEST requirements. Skip some tests if the installed mutan version is too old. The debug VM test still fails, probably because of an implementation bug.
172 lines
4.0 KiB
Go
172 lines
4.0 KiB
Go
package vm
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"math/big"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/ethcrypto"
|
|
"github.com/ethereum/go-ethereum/ethlog"
|
|
"github.com/ethereum/go-ethereum/ethstate"
|
|
"github.com/ethereum/go-ethereum/ethtrie"
|
|
"github.com/ethereum/go-ethereum/ethutil"
|
|
"github.com/obscuren/mutan"
|
|
)
|
|
|
|
type TestEnv struct{}
|
|
|
|
func (TestEnv) Origin() []byte { return nil }
|
|
func (TestEnv) BlockNumber() *big.Int { return nil }
|
|
func (TestEnv) BlockHash() []byte { return nil }
|
|
func (TestEnv) PrevHash() []byte { return nil }
|
|
func (TestEnv) Coinbase() []byte { return nil }
|
|
func (TestEnv) Time() int64 { return 0 }
|
|
func (TestEnv) GasLimit() *big.Int { return nil }
|
|
func (TestEnv) Difficulty() *big.Int { return nil }
|
|
func (TestEnv) Value() *big.Int { return nil }
|
|
func (TestEnv) AddLog(Log) {}
|
|
|
|
func (TestEnv) Transfer(from, to Account, amount *big.Int) error {
|
|
return nil
|
|
}
|
|
|
|
// This is likely to fail if anything ever gets looked up in the state trie :-)
|
|
func (TestEnv) State() *ethstate.State {
|
|
return ethstate.New(ethtrie.New(nil, ""))
|
|
}
|
|
|
|
const mutcode = `
|
|
var x = 0;
|
|
for i := 0; i < 10; i++ {
|
|
x = i
|
|
}
|
|
|
|
return x`
|
|
|
|
func setup(level ethlog.LogLevel, typ Type) (*Closure, VirtualMachine) {
|
|
code, err := ethutil.Compile(mutcode, true)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Pipe output to /dev/null
|
|
ethlog.AddLogSystem(ethlog.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level))
|
|
|
|
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
|
|
|
|
stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'})
|
|
callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0))
|
|
|
|
return callerClosure, New(TestEnv{}, typ)
|
|
}
|
|
|
|
var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009")
|
|
|
|
func TestDebugVm(t *testing.T) {
|
|
if mutan.Version < "0.6" {
|
|
t.Skip("skipping for mutan version", mutan.Version, " < 0.6")
|
|
}
|
|
|
|
closure, vm := setup(ethlog.DebugLevel, DebugVmTy)
|
|
ret, _, e := closure.Call(vm, nil)
|
|
if e != nil {
|
|
t.Fatalf("Call returned error: %v", e)
|
|
}
|
|
if !bytes.Equal(ret, big9) {
|
|
t.Errorf("Wrong return value '%x', want '%x'", ret, big9)
|
|
}
|
|
}
|
|
|
|
func TestVm(t *testing.T) {
|
|
if mutan.Version < "0.6" {
|
|
t.Skip("skipping for mutan version", mutan.Version, " < 0.6")
|
|
}
|
|
|
|
closure, vm := setup(ethlog.DebugLevel, StandardVmTy)
|
|
ret, _, e := closure.Call(vm, nil)
|
|
if e != nil {
|
|
t.Fatalf("Call returned error: %v", e)
|
|
}
|
|
if !bytes.Equal(ret, big9) {
|
|
t.Errorf("Wrong return value '%x', want '%x'", ret, big9)
|
|
}
|
|
}
|
|
|
|
func BenchmarkDebugVm(b *testing.B) {
|
|
closure, vm := setup(ethlog.InfoLevel, DebugVmTy)
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
closure.Call(vm, nil)
|
|
}
|
|
}
|
|
|
|
func BenchmarkVm(b *testing.B) {
|
|
closure, vm := setup(ethlog.InfoLevel, StandardVmTy)
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
closure.Call(vm, nil)
|
|
}
|
|
}
|
|
|
|
func RunCode(mutCode string, typ Type) []byte {
|
|
code, err := ethutil.Compile(mutCode, true)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.InfoLevel))
|
|
|
|
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
|
|
|
|
stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'})
|
|
closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0))
|
|
|
|
vm := New(TestEnv{}, typ)
|
|
ret, _, e := closure.Call(vm, nil)
|
|
if e != nil {
|
|
fmt.Println(e)
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func TestBuildInSha256(t *testing.T) {
|
|
ret := RunCode(`
|
|
var in = 42
|
|
var out = 0
|
|
|
|
call(0x2, 0, 10000, in, out)
|
|
|
|
return out
|
|
`, DebugVmTy)
|
|
|
|
exp := ethcrypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32))
|
|
if bytes.Compare(ret, exp) != 0 {
|
|
t.Errorf("Expected %x, got %x", exp, ret)
|
|
}
|
|
}
|
|
|
|
func TestBuildInRipemd(t *testing.T) {
|
|
ret := RunCode(`
|
|
var in = 42
|
|
var out = 0
|
|
|
|
call(0x3, 0, 10000, in, out)
|
|
|
|
return out
|
|
`, DebugVmTy)
|
|
|
|
exp := ethutil.RightPadBytes(ethcrypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32)
|
|
if bytes.Compare(ret, exp) != 0 {
|
|
t.Errorf("Expected %x, got %x", exp, ret)
|
|
}
|
|
}
|