diff --git a/ethchain/vm.go b/ethchain/vm.go index 5a15ba81be..6c30c94173 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,7 +53,8 @@ type Vm struct { type RuntimeVars struct { Origin []byte - BlockNumber uint64 + Block *Block + BlockNumber *big.Int PrevHash []byte Coinbase []byte Time int64 @@ -90,14 +91,14 @@ var isRequireError = false func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { // Recover from any require exception defer func() { - if r := recover(); r != nil /*&& isRequireError*/ { + if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) fmt.Println("vm err", err) } }() - ethutil.Config.Log.Debugf("[VM] Running %x\n", closure.object.Address()) + ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) // Memory for the current closure mem := &Memory{} @@ -128,7 +129,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro op := OpCode(val.Uint()) vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - //ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -188,7 +188,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: require(7) gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-2]) + addStepGasUsage(stack.data[stack.Len()-1]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -208,9 +208,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } if !closure.UseGas(gas) { - ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) + err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) - return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) + closure.UseGas(closure.Gas) + + return closure.Return(nil), err } vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) @@ -431,7 +433,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Printf(" => %d", l) case CALLDATACOPY: + panic("not implemented") case CODESIZE: + stack.Push(big.NewInt(int64(len(closure.Script)))) case CODECOPY: var ( size = int64(len(closure.Script)) @@ -461,7 +465,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case TIMESTAMP: stack.Push(big.NewInt(vm.vars.Time)) case NUMBER: - stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) + stack.Push(vm.vars.BlockNumber) case DIFFICULTY: stack.Push(vm.vars.Diff) case GASLIMIT: @@ -595,10 +599,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: // TODO RE-WRITE require(7) - // Closure addr - addr := stack.Pop() + + vm.Endl() + + gas := stack.Pop() // Pop gas and value of the stack. - gas, value := stack.Popn() + value, addr := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() // Pop return size and offset @@ -607,37 +613,34 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - snapshot := vm.state.Snapshot() + //snapshot := vm.state.Snapshot() - closure.object.Nonce += 1 if closure.object.Amount.Cmp(value) < 0 { ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { - // Fetch the contract which will serve as the closure body - contract := vm.state.GetStateObject(addr.Bytes()) + stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) - if contract != nil { - // Add the value to the state object - contract.AddAmount(value) + closure.object.SubAmount(value) + // Add the value to the state object + stateObject.AddAmount(value) - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.Revert(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - } else { - ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + // Create a new callable closure + closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := closure.Call(vm, args, hook) + if err != nil { stack.Push(ethutil.BigFalse) + + // Reset the changes applied this object + vm.state.ResetStateObject(stateObject) + + ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + } else { + stack.Push(ethutil.BigTrue) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } } case RETURN: @@ -645,6 +648,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) + vm.Printf(" => 0x%x", ret).Endl() + return closure.Return(ret), nil case SUICIDE: require(1) @@ -659,6 +664,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure + vm.Endl() + return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op)