From 20c742e47406c13ebc6427951f6fcf1b0056ea26 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 18 Oct 2014 13:31:20 +0200 Subject: Moved ethvm => vm --- vm/execution.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 vm/execution.go (limited to 'vm/execution.go') diff --git a/vm/execution.go b/vm/execution.go new file mode 100644 index 000000000..6bed43026 --- /dev/null +++ b/vm/execution.go @@ -0,0 +1,93 @@ +package vm + +import ( + "fmt" + "math/big" + + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +type Execution struct { + vm VirtualMachine + address, input []byte + Gas, price, value *big.Int + object *ethstate.StateObject +} + +func NewExecution(vm VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { + return &Execution{vm: vm, address: address, input: input, Gas: gas, price: gasPrice, value: value} +} + +func (self *Execution) Addr() []byte { + return self.address +} + +func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) ([]byte, error) { + // Retrieve the executing code + code := self.vm.Env().State().GetCode(codeAddr) + + return self.exec(code, codeAddr, caller) +} + +func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, err error) { + env := self.vm.Env() + + snapshot := env.State().Copy() + defer func() { + if err != nil { + env.State().Set(snapshot) + } + }() + + msg := env.State().Manifest().AddMessage(ðstate.Message{ + To: self.address, From: caller.Address(), + Input: self.input, + Origin: env.Origin(), + Block: env.BlockHash(), Timestamp: env.Time(), Coinbase: env.Coinbase(), Number: env.BlockNumber(), + Value: self.value, + }) + + object := caller.Object() + if object.Balance.Cmp(self.value) < 0 { + caller.ReturnGas(self.Gas, self.price) + + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance) + } else { + stateObject := env.State().GetOrNewStateObject(self.address) + self.object = stateObject + + caller.Object().SubAmount(self.value) + stateObject.AddAmount(self.value) + + // Pre-compiled contracts (address.go) 1, 2 & 3. + naddr := ethutil.BigD(caddr).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 { + // Create a new callable closure + c := NewClosure(msg, caller, stateObject, code, self.Gas, self.price) + c.exe = self + + if self.vm.Depth() == MaxCallDepth { + c.UseGas(c.Gas) + + return c.Return(nil), fmt.Errorf("Max call depth exceeded (%d)", MaxCallDepth) + } + + // Executer the closure and get the return value (if any) + ret, _, err = c.Call(self.vm, self.input) + + msg.Output = ret + } + } + + return +} + +func (self *Execution) Create(caller ClosureRef) (ret []byte, err error) { + return self.exec(self.input, nil, caller) +} -- cgit v1.2.3 From b5beb1aac11af92bfe0f3ed7560b9eb08495ed09 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 22 Oct 2014 15:22:21 +0200 Subject: added a transfer method to vm env --- vm/execution.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'vm/execution.go') diff --git a/vm/execution.go b/vm/execution.go index 6bed43026..4c4bd1e3c 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -48,17 +48,17 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, Value: self.value, }) - object := caller.Object() - if object.Balance.Cmp(self.value) < 0 { + from, to := caller.Object(), env.State().GetOrNewStateObject(self.address) + err = env.Transfer(from, to, self.value) + if err != nil { caller.ReturnGas(self.Gas, self.price) - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance) + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance) } else { - stateObject := env.State().GetOrNewStateObject(self.address) - self.object = stateObject + self.object = to - caller.Object().SubAmount(self.value) - stateObject.AddAmount(self.value) + //caller.Object().SubAmount(self.value) + //stateObject.AddAmount(self.value) // Pre-compiled contracts (address.go) 1, 2 & 3. naddr := ethutil.BigD(caddr).Uint64() @@ -69,7 +69,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, } } else { // Create a new callable closure - c := NewClosure(msg, caller, stateObject, code, self.Gas, self.price) + c := NewClosure(msg, caller, to, code, self.Gas, self.price) c.exe = self if self.vm.Depth() == MaxCallDepth { -- cgit v1.2.3 From 29b8a0bc5ffa7a674a06a211e1c8bdd1b6ed07b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Oct 2014 01:01:26 +0200 Subject: Updated the VM & VM tests * Stack Error shouldn't revert to previous state * Updated VM Test tool * Added Transfer method to VM Env --- vm/execution.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'vm/execution.go') diff --git a/vm/execution.go b/vm/execution.go index 4c4bd1e3c..bd174d64e 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -13,6 +13,7 @@ type Execution struct { address, input []byte Gas, price, value *big.Int object *ethstate.StateObject + SkipTransfer bool } func NewExecution(vm VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { @@ -49,17 +50,17 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, }) from, to := caller.Object(), env.State().GetOrNewStateObject(self.address) - err = env.Transfer(from, to, self.value) + // Skipping transfer is used on testing for the initial call + if !self.SkipTransfer { + err = env.Transfer(from, to, self.value) + } + if err != nil { caller.ReturnGas(self.Gas, self.price) err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance) } else { self.object = to - - //caller.Object().SubAmount(self.value) - //stateObject.AddAmount(self.value) - // Pre-compiled contracts (address.go) 1, 2 & 3. naddr := ethutil.BigD(caddr).Uint64() if p := Precompiled[naddr]; p != nil { @@ -73,14 +74,13 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, c.exe = self if self.vm.Depth() == MaxCallDepth { - c.UseGas(c.Gas) + c.UseGas(self.Gas) return c.Return(nil), fmt.Errorf("Max call depth exceeded (%d)", MaxCallDepth) } // Executer the closure and get the return value (if any) ret, _, err = c.Call(self.vm, self.input) - msg.Output = ret } } -- cgit v1.2.3 From feef194829b07570e91873ed5d1e8cc51e8fa430 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Oct 2014 14:04:00 +0200 Subject: Chnged to use GetOp instead & added error + checking --- vm/execution.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vm/execution.go') diff --git a/vm/execution.go b/vm/execution.go index bd174d64e..c518c4b57 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -36,7 +36,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, snapshot := env.State().Copy() defer func() { - if err != nil { + if IsDepthErr(err) || IsOOGErr(err) { env.State().Set(snapshot) } }() @@ -76,7 +76,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, if self.vm.Depth() == MaxCallDepth { c.UseGas(self.Gas) - return c.Return(nil), fmt.Errorf("Max call depth exceeded (%d)", MaxCallDepth) + return c.Return(nil), DepthError{} } // Executer the closure and get the return value (if any) -- cgit v1.2.3