aboutsummaryrefslogtreecommitdiffstats
path: root/vm/vm_debug.go
diff options
context:
space:
mode:
Diffstat (limited to 'vm/vm_debug.go')
-rw-r--r--vm/vm_debug.go245
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
-}