diff options
Diffstat (limited to 'vm/vm_debug.go')
-rw-r--r-- | vm/vm_debug.go | 245 |
1 files changed, 131 insertions, 114 deletions
diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 544e04a5f..fd16a3895 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -2,6 +2,7 @@ package vm import ( "fmt" + "math" "math/big" "github.com/ethereum/go-ethereum/crypto" @@ -25,8 +26,6 @@ type DebugVm struct { Fn string Recoverable bool - - depth int } func NewDebugVm(env Environment) *DebugVm { @@ -38,8 +37,21 @@ func NewDebugVm(env Environment) *DebugVm { return &DebugVm{env: env, logTy: lt, Recoverable: true} } -func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { - self.depth++ +func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { + self.env.SetDepth(self.env.Depth() + 1) + + msg := self.env.State().Manifest().AddMessage(&state.Message{ + To: me.Address(), From: caller.Address(), + Input: callData, + Origin: self.env.Origin(), + Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Value: value, + }) + closure := NewClosure(msg, caller, me, code, gas, price) + + if p := Precompiled[string(me.Address())]; p != nil { + return self.RunPrecompiled(p, callData, closure) + } if self.Recoverable { // Recover from any require exception @@ -60,35 +72,35 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { var ( op OpCode - destinations = analyseJumpDests(closure.Code) - mem = NewMemory() - stack = NewStack() - pc = big.NewInt(0) - step = 0 - prevStep = 0 - statedb = self.env.State() - require = func(m int) { + destinations = analyseJumpDests(closure.Code) + mem = NewMemory() + stack = NewStack() + pc uint64 = 0 + step = 0 + prevStep = 0 + statedb = self.env.State() + require = func(m int) { if stack.Len() < m { panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) } } - jump = func(from, to *big.Int) { - p := int(to.Int64()) + jump = func(from uint64, to *big.Int) { + p := to.Uint64() self.Printf(" ~> %v", to) // Return to start if p == 0 { - pc = big.NewInt(0) + pc = 0 } else { nop := OpCode(closure.GetOp(p)) - if !(nop == JUMPDEST || destinations[from.Int64()] != nil) { - panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) + if !(nop == JUMPDEST || destinations[from] != nil) { + panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p)) } else if nop == JUMP || nop == JUMPI { panic(fmt.Sprintf("not allowed to JUMP(I) in to JUMP")) } - pc = to + pc = to.Uint64() } @@ -96,17 +108,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } ) - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } - // Don't bother with the execution if there's no code. - if len(closure.Code) == 0 { + if len(code) == 0 { return closure.Return(nil), nil } - vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%d) (%x) %x gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], closure.Address(), closure.Gas, callData) for { prevStep = step @@ -115,26 +122,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { step++ // Get the memory location of pc - op = closure.GetOp(int(pc.Uint64())) - - // XXX Leave this Println intact. Don't change this to the log system. - // Used for creating diffs between implementations - if self.logTy == LogTyDiff { - switch op { - case STOP, RETURN, SUICIDE: - statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) - }) - } - - b := pc.Bytes() - if len(b) == 0 { - b = []byte{0} - } - - fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) - } + op = closure.GetOp(pc) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -151,7 +139,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Stack checks only case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1 require(1) - case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 + case ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 require(2) case ADDMOD, MULMOD: // 3 require(3) @@ -165,10 +153,17 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { n := int(op - LOG0) require(n + 2) - mSize, mStart := stack.Peekn() gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) - addStepGasUsage(new(big.Int).Add(mSize, mStart)) + + mSize, mStart := stack.Peekn() + addStepGasUsage(mSize) + + newMemSize = calcMemSize(mStart, mSize) + case EXP: + require(2) + + gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1))) // Gas only case STOP: gas.Set(ethutil.Big0) @@ -186,16 +181,16 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { var mult *big.Int y, x := stack.Peekn() - val := closure.GetStorage(x) - if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { + val := statedb.GetState(closure.Address(), x.Bytes()) + if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 mult = ethutil.Big3 - } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) + } else if len(val) > 0 && len(y.Bytes()) == 0 { + statedb.Refund(caller.Address(), GasSStoreRefund) mult = ethutil.Big0 } else { - // non 0 => non 0 + // non 0 => non 0 (or 0 => 0) mult = ethutil.Big1 } gas.Set(new(big.Int).Mul(mult, GasSStore)) @@ -255,6 +250,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize.Div(newMemSize, u256(32)) newMemSize.Mul(newMemSize, u256(32)) + switch op { + case CALLDATACOPY, CODECOPY, EXTCODECOPY: + addStepGasUsage(new(big.Int).Div(newMemSize, u256(32))) + case SHA3: + g := new(big.Int).Div(newMemSize, u256(32)) + g.Mul(g, GasSha3Byte) + addStepGasUsage(g) + } + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) memGasUsage.Mul(GasMemory, memGasUsage) @@ -262,7 +266,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { addStepGasUsage(memGasUsage) - mem.Resize(newMemSize.Uint64()) } } @@ -280,6 +283,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(nil), OOG(gas, tmp) } + mem.Resize(newMemSize.Uint64()) + switch op { // 0x20 range case ADD: @@ -576,8 +581,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => %x", caller) case CALLVALUE: - value := closure.exe.value - stack.Push(value) self.Printf(" => %v", value) @@ -585,30 +588,30 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { var ( offset = stack.Pop() data = make([]byte, 32) - lenData = big.NewInt(int64(len(closure.Args))) + lenData = big.NewInt(int64(len(callData))) ) if lenData.Cmp(offset) >= 0 { length := new(big.Int).Add(offset, ethutil.Big32) length = ethutil.BigMin(length, lenData) - copy(data, closure.Args[offset.Int64():length.Int64()]) + copy(data, callData[offset.Int64():length.Int64()]) } self.Printf(" => 0x%x", data) stack.Push(ethutil.BigD(data)) case CALLDATASIZE: - l := int64(len(closure.Args)) + l := int64(len(callData)) stack.Push(big.NewInt(l)) self.Printf(" => %d", l) case CALLDATACOPY: var ( - size = int64(len(closure.Args)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() + size = uint64(len(callData)) + mOff = stack.Pop().Uint64() + cOff = stack.Pop().Uint64() + l = stack.Pop().Uint64() ) if cOff > size { @@ -618,11 +621,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { l = 0 } - code := closure.Args[cOff : cOff+l] + code := callData[cOff : cOff+l] mem.Set(mOff, l, code) - self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) + self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, callData[cOff:cOff+l]) case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { @@ -648,17 +651,17 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } var ( - size = int64(len(code)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() + size = uint64(len(code)) + mOff = stack.Pop().Uint64() + cOff = stack.Pop().Uint64() + l = stack.Pop().Uint64() ) if cOff > size { cOff = 0 l = 0 } else if cOff+l > size { - l = 0 + l = uint64(math.Min(float64(cOff+l), float64(size))) } codeCopy := code[cOff : cOff+l] @@ -707,28 +710,25 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0x50 range case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - a := big.NewInt(int64(op) - int64(PUSH1) + 1) - pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, a) - val := ethutil.BigD(data.Bytes()) + //a := big.NewInt(int64(op) - int64(PUSH1) + 1) + a := uint64(op - PUSH1 + 1) + //pc.Add(pc, ethutil.Big1) + val := ethutil.BigD(closure.GetRangeValue(pc+1, a)) // Push value to stack stack.Push(val) - pc.Add(pc, a.Sub(a, big.NewInt(1))) + pc += a + //pc.Add(pc, a.Sub(a, big.NewInt(1))) step += int(op) - int(PUSH1) + 1 - self.Printf(" => 0x%x", data.Bytes()) + self.Printf(" => 0x%x", val.Bytes()) case POP: stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) - v := stack.Dupn(n) + stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) - - if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { - fmt.Println(toValue(v)) - } case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) x, y := stack.Swapn(n) @@ -737,13 +737,13 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) topics := make([][]byte, n) - mStart, mSize := stack.Pop().Int64(), stack.Pop().Int64() - data := mem.Geti(mStart, mSize) + mSize, mStart := stack.Popn() for i := 0; i < n; i++ { - topics[i] = stack.Pop().Bytes() + topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32) } - log := &state.Log{closure.Address(), topics, data} + data := mem.Geti(mStart.Int64(), mSize.Int64()) + log := &Log{closure.Address(), topics, data} self.env.AddLog(log) self.Printf(" => %v", log) @@ -756,7 +756,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case MSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack val, mStart := stack.Popn() - mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + mem.Set(mStart.Uint64(), 32, ethutil.BigToBytes(val, 256)) self.Printf(" => 0x%x", val) case MSTORE8: @@ -776,14 +776,10 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { val, loc := stack.Popn() statedb.SetState(closure.Address(), loc.Bytes(), val) - // Debug sessions are allowed to run without message - if closure.message != nil { - closure.message.AddStorageChange(loc.Bytes()) - } + closure.message.AddStorageChange(loc.Bytes()) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: - jump(pc, stack.Pop()) continue @@ -798,13 +794,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case JUMPDEST: case PC: - stack.Push(pc) + stack.Push(big.NewInt(int64(pc))) case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) case GAS: stack.Push(closure.Gas) // 0x60 range case CREATE: + var ( err error value = stack.Pop() @@ -826,17 +823,19 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { closure.UseGas(closure.Gas) - msg := NewExecution(self, addr, input, gas, closure.Price, value) - ret, err := msg.Create(closure) + ret, err, ref := self.env.Create(closure, addr, input, gas, price, value) if err != nil { stack.Push(ethutil.BigFalse) - // Revert the state as it was before. - //self.env.State().Set(snapshot) - self.Printf("CREATE err %v", err) } else { - msg.object.Code = ret + // gas < len(ret) * CreateDataGas == NO_CODE + dataGas := big.NewInt(int64(len(ret))) + dataGas.Mul(dataGas, GasCreateByte) + if closure.UseGas(dataGas) { + ref.SetCode(ret) + msg.Output = ret + } stack.Push(ethutil.BigD(addr)) } @@ -861,25 +860,27 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - var executeAddr []byte + var ( + ret []byte + err error + ) if op == CALLCODE { - executeAddr = closure.Address() + ret, err = self.env.CallCode(closure, addr.Bytes(), args, gas, price, value) } else { - executeAddr = addr.Bytes() + ret, err = self.env.Call(closure, addr.Bytes(), args, gas, price, value) } - msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) - ret, err := msg.Exec(addr.Bytes(), closure) if err != nil { stack.Push(ethutil.BigFalse) vmlogger.Debugln(err) } else { stack.Push(ethutil.BigTrue) + msg.Output = ret - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + mem.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - self.Printf("resume %x", closure.Address()) + self.Printf("resume %x (%v)", closure.Address(), closure.Gas) // Debug hook if self.Dbg != nil { @@ -894,10 +895,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(ret), nil case SUICIDE: - receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) + balance := statedb.GetBalance(closure.Address()) - receiver.AddAmount(statedb.GetBalance(closure.Address())) + self.Printf(" => (%x) %v", receiver.Address()[:4], balance) + + receiver.AddAmount(balance) statedb.Delete(closure.Address()) fallthrough @@ -908,19 +911,18 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { default: vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) - //panic(fmt.Sprintf("Invalid opcode %x", op)) closure.ReturnGas(big.NewInt(1), nil) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } - pc.Add(pc, ethutil.Big1) + pc++ self.Endl() if self.Dbg != nil { for _, instrNo := range self.Dbg.BreakPoints() { - if pc.Cmp(big.NewInt(instrNo)) == 0 { + if pc == uint64(instrNo) { self.Stepping = true if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { @@ -937,6 +939,25 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } } +func (self *DebugVm) RunPrecompiled(p *PrecompiledAccount, callData []byte, closure *Closure) (ret []byte, err error) { + gas := p.Gas(len(callData)) + if closure.UseGas(gas) { + ret = p.Call(callData) + self.Printf("NATIVE_FUNC => %x", ret) + self.Endl() + + return closure.Return(ret), nil + } else { + self.Endl() + + tmp := new(big.Int).Set(closure.Gas) + + closure.UseGas(closure.Gas) + + return closure.Return(nil), OOG(gas, tmp) + } +} + func (self *DebugVm) Printf(format string, v ...interface{}) VirtualMachine { if self.logTy == LogTyPretty { self.logStr += fmt.Sprintf(format, v...) @@ -957,7 +978,3 @@ func (self *DebugVm) Endl() VirtualMachine { func (self *DebugVm) Env() Environment { return self.env } - -func (self *DebugVm) Depth() int { - return self.depth -} |