From f55e39cf1ae138f7698d8dce3aeee5eaa3f87a7d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 14 Oct 2014 13:37:26 +0200 Subject: [PATCH] Tests for native function calling --- ethvm/address.go | 2 - ethvm/execution.go | 4 +- ethvm/virtual_machine.go | 2 + ethvm/vm.go | 3 ++ ethvm/vm_debug.go | 4 +- ethvm/vm_test.go | 79 +++++++++++++++++++++++++++++++++++----- 6 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ethvm/address.go b/ethvm/address.go index 51e0d1cd7..f987c4761 100644 --- a/ethvm/address.go +++ b/ethvm/address.go @@ -26,8 +26,6 @@ var Precompiled = map[uint64]*PrecompiledAddress{ 3: &PrecompiledAddress{big.NewInt(100), ripemd160Func}, } -var NoAddr = PrecompiledAddress{} - func sha256Func(in []byte) []byte { return ethcrypto.Sha256(in) } diff --git a/ethvm/execution.go b/ethvm/execution.go index 84bc50778..6273fc49e 100644 --- a/ethvm/execution.go +++ b/ethvm/execution.go @@ -50,9 +50,11 @@ func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err stateObject.AddAmount(self.value) // Precompiled contracts (address.go) 1, 2 & 3. - if p := Precompiled[ethutil.BigD(codeAddr).Uint64()]; p != nil { + naddr := ethutil.BigD(codeAddr).Uint64() + if p := Precompiled[naddr]; p != nil { if self.gas.Cmp(p.Gas) >= 0 { ret = p.Call(self.input) + self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret) } } else { if self.vm.Depth() == MaxCallDepth { diff --git a/ethvm/virtual_machine.go b/ethvm/virtual_machine.go index 6dd837049..dd2e568cf 100644 --- a/ethvm/virtual_machine.go +++ b/ethvm/virtual_machine.go @@ -4,4 +4,6 @@ type VirtualMachine interface { Env() Environment RunClosure(*Closure) ([]byte, error) Depth() int + Printf(string, ...interface{}) VirtualMachine + Endl() VirtualMachine } diff --git a/ethvm/vm.go b/ethvm/vm.go index 0fb97e652..8d58ffcb7 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -694,3 +694,6 @@ func (self *Vm) Env() Environment { func (self *Vm) Depth() int { return self.depth } + +func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine { return self } +func (self *Vm) Endl() VirtualMachine { return self } diff --git a/ethvm/vm_debug.go b/ethvm/vm_debug.go index 8892ed6b8..0a1e0155e 100644 --- a/ethvm/vm_debug.go +++ b/ethvm/vm_debug.go @@ -846,7 +846,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } } -func (self *DebugVm) Printf(format string, v ...interface{}) *DebugVm { +func (self *DebugVm) Printf(format string, v ...interface{}) VirtualMachine { if self.logTy == LogTyPretty { self.logStr += fmt.Sprintf(format, v...) } @@ -854,7 +854,7 @@ func (self *DebugVm) Printf(format string, v ...interface{}) *DebugVm { return self } -func (self *DebugVm) Endl() *DebugVm { +func (self *DebugVm) Endl() VirtualMachine { if self.logTy == LogTyPretty { vmlogger.Debugln(self.logStr) self.logStr = "" diff --git a/ethvm/vm_test.go b/ethvm/vm_test.go index 4f30ab39b..cf4e2e5e7 100644 --- a/ethvm/vm_test.go +++ b/ethvm/vm_test.go @@ -1,29 +1,35 @@ package ethvm import ( + "bytes" "fmt" "io/ioutil" "log" "math/big" + "os" "testing" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" ) type TestEnv struct { } -func (self TestEnv) Origin() []byte { return nil } -func (self TestEnv) BlockNumber() *big.Int { return nil } -func (self TestEnv) BlockHash() []byte { return nil } -func (self TestEnv) PrevHash() []byte { return nil } -func (self TestEnv) Coinbase() []byte { return nil } -func (self TestEnv) Time() int64 { return 0 } -func (self TestEnv) Difficulty() *big.Int { return nil } -func (self TestEnv) Value() *big.Int { return nil } -func (self TestEnv) State() *ethstate.State { return nil } +func (self TestEnv) Origin() []byte { return nil } +func (self TestEnv) BlockNumber() *big.Int { return nil } +func (self TestEnv) BlockHash() []byte { return nil } +func (self TestEnv) PrevHash() []byte { return nil } +func (self TestEnv) Coinbase() []byte { return nil } +func (self TestEnv) Time() int64 { return 0 } +func (self TestEnv) Difficulty() *big.Int { return nil } +func (self TestEnv) Value() *big.Int { return nil } + +// This is likely to fail if anything ever gets looked up in the state trie :-) +func (self TestEnv) State() *ethstate.State { return ethstate.New(ethtrie.New(nil, "")) } const mutcode = ` var x = 0; @@ -93,3 +99,58 @@ func BenchmarkVm(b *testing.B) { closure.Call(vm, nil) } } + +func RunCode(mutCode string, typ Type) []byte { + code, err := ethutil.Compile(mutCode, true) + if err != nil { + log.Fatal(err) + } + + // Pipe output to /dev/null + ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.LogLevel(4))) + + 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) + } +}