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.go154
1 files changed, 85 insertions, 69 deletions
diff --git a/vm/vm_debug.go b/vm/vm_debug.go
index 0a541a769..aa3291e66 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 {
@@ -50,10 +49,8 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
})
closure := NewClosure(msg, caller, me, code, gas, price)
- if self.env.Depth() == MaxCallDepth {
- closure.UseGas(gas)
-
- return closure.Return(nil), DepthError{}
+ if p := Precompiled[string(me.Address())]; p != nil {
+ return self.RunPrecompiled(p, callData, closure)
}
if self.Recoverable {
@@ -98,7 +95,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
} else {
nop := OpCode(closure.GetOp(p))
if !(nop == JUMPDEST || destinations[from] != nil) {
- panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p))
+ 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"))
}
@@ -111,13 +108,13 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
}
)
+ vmlogger.Debugf("(%d) (%x) %x (code=%d) gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], closure.Address(), len(code), closure.Gas, callData)
+
// Don't bother with the execution if there's no code.
if len(code) == 0 {
return closure.Return(nil), nil
}
- vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, callData)
-
for {
prevStep = step
// The base for all big integer arithmetic
@@ -137,6 +134,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
addStepGasUsage(GasStep)
var newMemSize *big.Int = ethutil.Big0
+ var additionalGas *big.Int = new(big.Int)
// Stack Check, memory resize & gas phase
switch op {
// Stack checks only
@@ -166,13 +164,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
case EXP:
require(2)
- exp := new(big.Int).Set(stack.data[stack.Len()-2])
- nbytes := 0
- for exp.Cmp(ethutil.Big0) > 0 {
- nbytes += 1
- exp.Rsh(exp, 8)
- }
- gas.Set(big.NewInt(int64(nbytes + 1)))
+ gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1)))
// Gas only
case STOP:
gas.Set(ethutil.Big0)
@@ -190,16 +182,16 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
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))
@@ -222,22 +214,24 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
case SHA3:
require(2)
-
gas.Set(GasSha)
-
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
+ additionalGas.Set(stack.data[stack.Len()-2])
case CALLDATACOPY:
require(2)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
+ additionalGas.Set(stack.data[stack.Len()-3])
case CODECOPY:
require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
+ additionalGas.Set(stack.data[stack.Len()-3])
case EXTCODECOPY:
require(4)
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
+ additionalGas.Set(stack.data[stack.Len()-4])
case CALL, CALLCODE:
require(7)
gas.Set(GasCall)
@@ -254,17 +248,23 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
}
+ switch op {
+ case CALLDATACOPY, CODECOPY, EXTCODECOPY:
+ additionalGas.Add(additionalGas, u256(31))
+ additionalGas.Div(additionalGas, u256(32))
+ addStepGasUsage(additionalGas)
+ case SHA3:
+ additionalGas.Add(additionalGas, u256(31))
+ additionalGas.Div(additionalGas, u256(32))
+ additionalGas.Mul(additionalGas, GasSha3Byte)
+ addStepGasUsage(additionalGas)
+ }
+
if newMemSize.Cmp(ethutil.Big0) > 0 {
newMemSize.Add(newMemSize, u256(31))
newMemSize.Div(newMemSize, u256(32))
newMemSize.Mul(newMemSize, u256(32))
- switch op {
- // Additional gas usage on *CODPY
- case CALLDATACOPY, CODECOPY, EXTCODECOPY:
- addStepGasUsage(new(big.Int).Div(newMemSize, u256(32)))
- }
-
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
memGasUsage.Mul(GasMemory, memGasUsage)
@@ -614,10 +614,10 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
self.Printf(" => %d", l)
case CALLDATACOPY:
var (
- size = int64(len(callData))
- 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 {
@@ -649,32 +649,29 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
case CODECOPY, EXTCODECOPY:
var code []byte
if op == EXTCODECOPY {
- addr := stack.Pop().Bytes()
-
- code = statedb.GetCode(addr)
+ code = statedb.GetCode(stack.Pop().Bytes())
} else {
code = closure.Code
}
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]
mem.Set(mOff, l, codeCopy)
- self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l])
+ self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy)
case GASPRICE:
stack.Push(closure.Price)
@@ -719,8 +716,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
//a := big.NewInt(int64(op) - int64(PUSH1) + 1)
a := uint64(op - PUSH1 + 1)
//pc.Add(pc, ethutil.Big1)
- data := closure.GetRangeValue(pc+1, a)
- val := ethutil.BigD(data.Bytes())
+ val := ethutil.BigD(closure.GetRangeValue(pc+1, a))
// Push value to stack
stack.Push(val)
pc += a
@@ -728,7 +724,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
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:
@@ -744,12 +740,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
topics := make([][]byte, n)
- mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64()
- data := mem.Geti(mStart, mSize)
+ mSize, mStart := stack.Popn()
for i := 0; i < n; i++ {
topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32)
}
+ data := mem.Geti(mStart.Int64(), mSize.Int64())
log := &Log{closure.Address(), topics, data}
self.env.AddLog(log)
@@ -763,7 +759,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
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:
@@ -783,10 +779,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
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:
@@ -839,8 +832,13 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
self.Printf("CREATE err %v", err)
} else {
- ref.SetCode(ret)
- msg.Output = 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))
}
@@ -865,14 +863,16 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
// 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)
}
- ret, err := self.env.Call(closure, executeAddr, args, gas, price, value)
if err != nil {
stack.Push(ethutil.BigFalse)
@@ -881,9 +881,9 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
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,14 +894,16 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
size, offset := stack.Popn()
ret := mem.Get(offset.Int64(), size.Int64())
- self.Printf(" => (%d) 0x%x", len(ret), ret).Endl()
+ self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl()
return closure.Return(ret), nil
case SUICIDE:
-
receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes())
+ balance := statedb.GetBalance(closure.Address())
+
+ self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
- receiver.AddAmount(statedb.GetBalance(closure.Address()))
+ receiver.AddAmount(balance)
statedb.Delete(closure.Address())
fallthrough
@@ -912,7 +914,6 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
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)
@@ -941,6 +942,25 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
}
}
+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...)
@@ -961,7 +981,3 @@ func (self *DebugVm) Endl() VirtualMachine {
func (self *DebugVm) Env() Environment {
return self.env
}
-
-func (self *DebugVm) Depth() int {
- return self.depth
-}