forked from mirror/go-ethereum
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
923 lines
19 KiB
923 lines
19 KiB
10 years ago
|
package vm
|
||
10 years ago
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math/big"
|
||
|
|
||
|
"github.com/ethereum/eth-go/ethcrypto"
|
||
|
"github.com/ethereum/eth-go/ethutil"
|
||
|
)
|
||
|
|
||
|
type DebugVm struct {
|
||
|
env Environment
|
||
|
|
||
|
logTy byte
|
||
|
logStr string
|
||
|
|
||
|
err error
|
||
|
|
||
|
// Debugging
|
||
|
Dbg Debugger
|
||
|
|
||
|
BreakPoints []int64
|
||
|
Stepping bool
|
||
|
Fn string
|
||
|
|
||
|
Recoverable bool
|
||
|
|
||
|
depth int
|
||
|
}
|
||
|
|
||
|
func NewDebugVm(env Environment) *DebugVm {
|
||
|
lt := LogTyPretty
|
||
|
if ethutil.Config.Diff {
|
||
|
lt = LogTyDiff
|
||
|
}
|
||
|
|
||
|
return &DebugVm{env: env, logTy: lt, Recoverable: true}
|
||
|
}
|
||
|
|
||
|
func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||
|
self.depth++
|
||
|
|
||
10 years ago
|
var (
|
||
|
op OpCode
|
||
|
|
||
|
mem = &Memory{}
|
||
|
stack = NewStack()
|
||
|
pc = big.NewInt(0)
|
||
|
step = 0
|
||
|
prevStep = 0
|
||
10 years ago
|
state = self.env.State()
|
||
10 years ago
|
require = func(m int) {
|
||
|
if stack.Len() < m {
|
||
|
panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m))
|
||
|
}
|
||
|
}
|
||
10 years ago
|
|
||
|
jump = func(pos *big.Int) {
|
||
|
p := int(pos.Int64())
|
||
|
|
||
|
self.Printf(" ~> %v", pos)
|
||
|
// Return to start
|
||
|
if p == 0 {
|
||
|
pc = big.NewInt(0)
|
||
|
} else {
|
||
|
nop := OpCode(closure.GetOp(p - 1))
|
||
|
if nop != JUMPDEST {
|
||
|
panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p))
|
||
|
}
|
||
|
|
||
|
pc = pos
|
||
|
}
|
||
|
|
||
|
self.Endl()
|
||
|
}
|
||
10 years ago
|
)
|
||
|
|
||
10 years ago
|
if self.Recoverable {
|
||
|
// Recover from any require exception
|
||
|
defer func() {
|
||
|
if r := recover(); r != nil {
|
||
10 years ago
|
self.Endl()
|
||
|
|
||
10 years ago
|
ret = closure.Return(nil)
|
||
|
err = fmt.Errorf("%v", r)
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
|
||
|
// 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 {
|
||
|
return closure.Return(nil), nil
|
||
|
}
|
||
|
|
||
|
vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", self.Fn, closure.Address(), closure.Gas, closure.Args)
|
||
|
|
||
|
for {
|
||
|
prevStep = step
|
||
|
// The base for all big integer arithmetic
|
||
|
base := new(big.Int)
|
||
|
|
||
|
step++
|
||
|
// Get the memory location of pc
|
||
|
op := OpCode(closure.Get(pc).Uint())
|
||
|
|
||
|
// 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:
|
||
10 years ago
|
state.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) {
|
||
10 years ago
|
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())
|
||
|
}
|
||
|
|
||
|
gas := new(big.Int)
|
||
|
addStepGasUsage := func(amount *big.Int) {
|
||
|
if amount.Cmp(ethutil.Big0) >= 0 {
|
||
|
gas.Add(gas, amount)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
addStepGasUsage(GasStep)
|
||
|
|
||
|
var newMemSize *big.Int = ethutil.Big0
|
||
|
switch op {
|
||
|
case STOP:
|
||
|
gas.Set(ethutil.Big0)
|
||
|
case SUICIDE:
|
||
|
gas.Set(ethutil.Big0)
|
||
|
case SLOAD:
|
||
|
gas.Set(GasSLoad)
|
||
|
case SSTORE:
|
||
|
var mult *big.Int
|
||
|
y, x := stack.Peekn()
|
||
|
val := closure.GetStorage(x)
|
||
|
if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 {
|
||
|
mult = ethutil.Big2
|
||
|
} else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 {
|
||
|
mult = ethutil.Big0
|
||
|
} else {
|
||
|
mult = ethutil.Big1
|
||
|
}
|
||
|
gas = new(big.Int).Mul(mult, GasSStore)
|
||
|
case BALANCE:
|
||
|
gas.Set(GasBalance)
|
||
|
case MSTORE:
|
||
|
require(2)
|
||
|
newMemSize = calcMemSize(stack.Peek(), u256(32))
|
||
|
case MLOAD:
|
||
|
require(1)
|
||
|
|
||
|
newMemSize = calcMemSize(stack.Peek(), u256(32))
|
||
|
case MSTORE8:
|
||
|
require(2)
|
||
|
newMemSize = calcMemSize(stack.Peek(), u256(1))
|
||
|
case RETURN:
|
||
|
require(2)
|
||
|
|
||
|
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])
|
||
|
case CALLDATACOPY:
|
||
|
require(2)
|
||
|
|
||
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
|
||
|
case CODECOPY:
|
||
|
require(3)
|
||
|
|
||
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
|
||
|
case EXTCODECOPY:
|
||
|
require(4)
|
||
|
|
||
|
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
|
||
|
case CALL, CALLCODE:
|
||
|
require(7)
|
||
|
gas.Set(GasCall)
|
||
|
addStepGasUsage(stack.data[stack.Len()-1])
|
||
|
|
||
|
x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7])
|
||
|
y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5])
|
||
|
|
||
|
newMemSize = ethutil.BigMax(x, y)
|
||
|
case CREATE:
|
||
|
require(3)
|
||
|
gas.Set(GasCreate)
|
||
|
|
||
|
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
|
||
|
}
|
||
|
|
||
|
if newMemSize.Cmp(ethutil.Big0) > 0 {
|
||
|
newMemSize.Add(newMemSize, u256(31))
|
||
|
newMemSize.Div(newMemSize, u256(32))
|
||
|
newMemSize.Mul(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)
|
||
|
memGasUsage.Div(memGasUsage, u256(32))
|
||
|
|
||
|
addStepGasUsage(memGasUsage)
|
||
|
}
|
||
|
}
|
||
|
|
||
10 years ago
|
self.Printf("(pc) %-3d -o- %-14s", pc, op.String())
|
||
|
self.Printf(" (g) %-3v (%v)", gas, closure.Gas)
|
||
|
|
||
10 years ago
|
if !closure.UseGas(gas) {
|
||
10 years ago
|
self.Endl()
|
||
|
|
||
10 years ago
|
err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas)
|
||
|
|
||
|
closure.UseGas(closure.Gas)
|
||
|
|
||
|
return closure.Return(nil), err
|
||
|
}
|
||
|
|
||
|
mem.Resize(newMemSize.Uint64())
|
||
|
|
||
|
switch op {
|
||
|
case LOG:
|
||
|
stack.Print()
|
||
|
mem.Print()
|
||
|
// 0x20 range
|
||
|
case ADD:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v + %v", y, x)
|
||
|
|
||
|
base.Add(y, x)
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
// Pop result back on the stack
|
||
|
stack.Push(base)
|
||
|
case SUB:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v - %v", y, x)
|
||
|
|
||
|
base.Sub(y, x)
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
// Pop result back on the stack
|
||
|
stack.Push(base)
|
||
|
case MUL:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v * %v", y, x)
|
||
|
|
||
|
base.Mul(y, x)
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
// Pop result back on the stack
|
||
|
stack.Push(base)
|
||
|
case DIV:
|
||
|
require(2)
|
||
10 years ago
|
x, y := stack.Pop(), stack.Pop()
|
||
|
self.Printf(" %v / %v", x, y)
|
||
10 years ago
|
|
||
10 years ago
|
if y.Cmp(ethutil.Big0) != 0 {
|
||
|
base.Div(x, y)
|
||
10 years ago
|
}
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
// Pop result back on the stack
|
||
|
stack.Push(base)
|
||
|
case SDIV:
|
||
|
require(2)
|
||
10 years ago
|
x, y := S256(stack.Pop()), S256(stack.Pop())
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" %v / %v", x, y)
|
||
|
|
||
|
if y.Cmp(ethutil.Big0) == 0 {
|
||
|
base.Set(ethutil.Big0)
|
||
|
} else {
|
||
|
n := new(big.Int)
|
||
|
if new(big.Int).Mul(x, y).Cmp(ethutil.Big0) < 0 {
|
||
|
n.SetInt64(-1)
|
||
|
} else {
|
||
|
n.SetInt64(1)
|
||
|
}
|
||
10 years ago
|
|
||
10 years ago
|
base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
|
||
|
|
||
|
U256(base)
|
||
|
}
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
stack.Push(base)
|
||
|
case MOD:
|
||
|
require(2)
|
||
10 years ago
|
x, y := stack.Pop(), stack.Pop()
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" %v %% %v", x, y)
|
||
10 years ago
|
|
||
10 years ago
|
if y.Cmp(ethutil.Big0) == 0 {
|
||
|
base.Set(ethutil.Big0)
|
||
|
} else {
|
||
|
base.Mod(x, y)
|
||
|
}
|
||
10 years ago
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
stack.Push(base)
|
||
|
case SMOD:
|
||
|
require(2)
|
||
10 years ago
|
x, y := S256(stack.Pop()), S256(stack.Pop())
|
||
|
|
||
|
self.Printf(" %v %% %v", x, y)
|
||
10 years ago
|
|
||
10 years ago
|
if y.Cmp(ethutil.Big0) == 0 {
|
||
|
base.Set(ethutil.Big0)
|
||
|
} else {
|
||
|
n := new(big.Int)
|
||
|
if x.Cmp(ethutil.Big0) < 0 {
|
||
|
n.SetInt64(-1)
|
||
|
} else {
|
||
|
n.SetInt64(1)
|
||
|
}
|
||
10 years ago
|
|
||
10 years ago
|
base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
|
||
10 years ago
|
|
||
10 years ago
|
U256(base)
|
||
|
}
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
stack.Push(base)
|
||
|
|
||
|
case EXP:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
|
||
|
self.Printf(" %v ** %v", y, x)
|
||
|
|
||
|
base.Exp(y, x, Pow256)
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
|
||
|
stack.Push(base)
|
||
|
case NEG:
|
||
|
require(1)
|
||
|
base.Sub(Pow256, stack.Pop())
|
||
10 years ago
|
|
||
|
base = U256(base)
|
||
|
|
||
10 years ago
|
stack.Push(base)
|
||
|
case LT:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v < %v", y, x)
|
||
|
// x < y
|
||
|
if y.Cmp(x) < 0 {
|
||
|
stack.Push(ethutil.BigTrue)
|
||
|
} else {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
}
|
||
|
case GT:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v > %v", y, x)
|
||
|
|
||
|
// x > y
|
||
|
if y.Cmp(x) > 0 {
|
||
|
stack.Push(ethutil.BigTrue)
|
||
|
} else {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
}
|
||
|
|
||
|
case SLT:
|
||
|
require(2)
|
||
10 years ago
|
y, x := S256(stack.Pop()), S256(stack.Pop())
|
||
10 years ago
|
self.Printf(" %v < %v", y, x)
|
||
|
// x < y
|
||
10 years ago
|
if y.Cmp(S256(x)) < 0 {
|
||
10 years ago
|
stack.Push(ethutil.BigTrue)
|
||
|
} else {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
}
|
||
|
case SGT:
|
||
|
require(2)
|
||
10 years ago
|
y, x := S256(stack.Pop()), S256(stack.Pop())
|
||
10 years ago
|
self.Printf(" %v > %v", y, x)
|
||
|
|
||
|
// x > y
|
||
|
if y.Cmp(x) > 0 {
|
||
|
stack.Push(ethutil.BigTrue)
|
||
|
} else {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
}
|
||
|
|
||
|
case EQ:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v == %v", y, x)
|
||
|
|
||
|
// x == y
|
||
|
if x.Cmp(y) == 0 {
|
||
|
stack.Push(ethutil.BigTrue)
|
||
|
} else {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
}
|
||
|
case NOT:
|
||
|
require(1)
|
||
|
x := stack.Pop()
|
||
|
if x.Cmp(ethutil.BigFalse) > 0 {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
} else {
|
||
|
stack.Push(ethutil.BigTrue)
|
||
|
}
|
||
|
|
||
|
// 0x10 range
|
||
|
case AND:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v & %v", y, x)
|
||
|
|
||
|
stack.Push(base.And(y, x))
|
||
|
case OR:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v | %v", y, x)
|
||
|
|
||
|
stack.Push(base.Or(y, x))
|
||
|
case XOR:
|
||
|
require(2)
|
||
|
x, y := stack.Popn()
|
||
|
self.Printf(" %v ^ %v", y, x)
|
||
|
|
||
|
stack.Push(base.Xor(y, x))
|
||
|
case BYTE:
|
||
|
require(2)
|
||
|
val, th := stack.Popn()
|
||
10 years ago
|
|
||
|
if th.Cmp(big.NewInt(32)) < 0 {
|
||
10 years ago
|
byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
||
|
|
||
10 years ago
|
base.Set(byt)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
base.Set(ethutil.BigFalse)
|
||
10 years ago
|
}
|
||
10 years ago
|
|
||
|
self.Printf(" => 0x%x", base.Bytes())
|
||
|
|
||
|
stack.Push(base)
|
||
10 years ago
|
case ADDMOD:
|
||
|
require(3)
|
||
|
|
||
|
x := stack.Pop()
|
||
|
y := stack.Pop()
|
||
|
z := stack.Pop()
|
||
|
|
||
|
base.Add(x, y)
|
||
|
base.Mod(base, z)
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
|
||
|
stack.Push(base)
|
||
|
case MULMOD:
|
||
|
require(3)
|
||
|
|
||
|
x := stack.Pop()
|
||
|
y := stack.Pop()
|
||
|
z := stack.Pop()
|
||
|
|
||
|
base.Mul(x, y)
|
||
|
base.Mod(base, z)
|
||
|
|
||
10 years ago
|
U256(base)
|
||
10 years ago
|
|
||
|
self.Printf(" = %v", base)
|
||
|
|
||
|
stack.Push(base)
|
||
|
|
||
|
// 0x20 range
|
||
|
case SHA3:
|
||
|
require(2)
|
||
|
size, offset := stack.Popn()
|
||
|
data := ethcrypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
|
||
|
|
||
|
stack.Push(ethutil.BigD(data))
|
||
|
|
||
|
self.Printf(" => %x", data)
|
||
|
// 0x30 range
|
||
|
case ADDRESS:
|
||
|
stack.Push(ethutil.BigD(closure.Address()))
|
||
|
|
||
|
self.Printf(" => %x", closure.Address())
|
||
|
case BALANCE:
|
||
|
require(1)
|
||
|
|
||
|
addr := stack.Pop().Bytes()
|
||
10 years ago
|
balance := state.GetBalance(addr)
|
||
10 years ago
|
|
||
|
stack.Push(balance)
|
||
|
|
||
|
self.Printf(" => %v (%x)", balance, addr)
|
||
|
case ORIGIN:
|
||
|
origin := self.env.Origin()
|
||
|
|
||
|
stack.Push(ethutil.BigD(origin))
|
||
|
|
||
|
self.Printf(" => %x", origin)
|
||
|
case CALLER:
|
||
|
caller := closure.caller.Address()
|
||
|
stack.Push(ethutil.BigD(caller))
|
||
|
|
||
|
self.Printf(" => %x", caller)
|
||
|
case CALLVALUE:
|
||
10 years ago
|
value := closure.exe.value
|
||
10 years ago
|
|
||
|
stack.Push(value)
|
||
|
|
||
|
self.Printf(" => %v", value)
|
||
|
case CALLDATALOAD:
|
||
|
require(1)
|
||
|
var (
|
||
|
offset = stack.Pop()
|
||
|
data = make([]byte, 32)
|
||
|
lenData = big.NewInt(int64(len(closure.Args)))
|
||
|
)
|
||
|
|
||
|
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()])
|
||
|
}
|
||
|
|
||
|
self.Printf(" => 0x%x", data)
|
||
|
|
||
|
stack.Push(ethutil.BigD(data))
|
||
|
case CALLDATASIZE:
|
||
|
l := int64(len(closure.Args))
|
||
|
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()
|
||
|
)
|
||
|
|
||
|
if cOff > size {
|
||
|
cOff = 0
|
||
|
l = 0
|
||
|
} else if cOff+l > size {
|
||
|
l = 0
|
||
|
}
|
||
|
|
||
|
code := closure.Args[cOff : cOff+l]
|
||
|
|
||
|
mem.Set(mOff, l, code)
|
||
|
case CODESIZE, EXTCODESIZE:
|
||
|
var code []byte
|
||
10 years ago
|
if op == EXTCODESIZE {
|
||
10 years ago
|
addr := stack.Pop().Bytes()
|
||
|
|
||
10 years ago
|
code = state.GetCode(addr)
|
||
10 years ago
|
} else {
|
||
|
code = closure.Code
|
||
|
}
|
||
|
|
||
|
l := big.NewInt(int64(len(code)))
|
||
|
stack.Push(l)
|
||
|
|
||
|
self.Printf(" => %d", l)
|
||
|
case CODECOPY, EXTCODECOPY:
|
||
|
var code []byte
|
||
|
if op == EXTCODECOPY {
|
||
|
addr := stack.Pop().Bytes()
|
||
|
|
||
10 years ago
|
code = state.GetCode(addr)
|
||
10 years ago
|
} else {
|
||
|
code = closure.Code
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
size = int64(len(code))
|
||
|
mOff = stack.Pop().Int64()
|
||
|
cOff = stack.Pop().Int64()
|
||
|
l = stack.Pop().Int64()
|
||
|
)
|
||
|
|
||
|
if cOff > size {
|
||
|
cOff = 0
|
||
|
l = 0
|
||
|
} else if cOff+l > size {
|
||
|
l = 0
|
||
|
}
|
||
|
|
||
|
codeCopy := code[cOff : cOff+l]
|
||
|
|
||
|
mem.Set(mOff, l, codeCopy)
|
||
|
case GASPRICE:
|
||
|
stack.Push(closure.Price)
|
||
|
|
||
|
self.Printf(" => %v", closure.Price)
|
||
|
|
||
|
// 0x40 range
|
||
|
case PREVHASH:
|
||
|
prevHash := self.env.PrevHash()
|
||
|
|
||
|
stack.Push(ethutil.BigD(prevHash))
|
||
|
|
||
|
self.Printf(" => 0x%x", prevHash)
|
||
|
case COINBASE:
|
||
|
coinbase := self.env.Coinbase()
|
||
|
|
||
|
stack.Push(ethutil.BigD(coinbase))
|
||
|
|
||
|
self.Printf(" => 0x%x", coinbase)
|
||
|
case TIMESTAMP:
|
||
|
time := self.env.Time()
|
||
|
|
||
|
stack.Push(big.NewInt(time))
|
||
|
|
||
|
self.Printf(" => 0x%x", time)
|
||
|
case NUMBER:
|
||
|
number := self.env.BlockNumber()
|
||
|
|
||
|
stack.Push(number)
|
||
|
|
||
|
self.Printf(" => 0x%x", number.Bytes())
|
||
|
case DIFFICULTY:
|
||
|
difficulty := self.env.Difficulty()
|
||
|
|
||
|
stack.Push(difficulty)
|
||
|
|
||
|
self.Printf(" => 0x%x", difficulty.Bytes())
|
||
|
case GASLIMIT:
|
||
10 years ago
|
stack.Push(self.env.GasLimit())
|
||
10 years ago
|
|
||
|
// 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())
|
||
|
// Push value to stack
|
||
|
stack.Push(val)
|
||
|
pc.Add(pc, a.Sub(a, big.NewInt(1)))
|
||
|
|
||
|
step += int(op) - int(PUSH1) + 1
|
||
|
|
||
|
self.Printf(" => 0x%x", data.Bytes())
|
||
|
case POP:
|
||
|
require(1)
|
||
|
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)
|
||
|
|
||
|
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)
|
||
|
|
||
|
self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes())
|
||
|
case MLOAD:
|
||
|
require(1)
|
||
|
offset := stack.Pop()
|
||
|
val := ethutil.BigD(mem.Get(offset.Int64(), 32))
|
||
|
stack.Push(val)
|
||
|
|
||
|
self.Printf(" => 0x%x", val.Bytes())
|
||
|
case MSTORE: // Store the value at stack top-1 in to memory at location stack top
|
||
|
require(2)
|
||
|
// Pop value of the stack
|
||
|
val, mStart := stack.Popn()
|
||
|
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
|
||
|
|
||
|
self.Printf(" => 0x%x", val)
|
||
|
case MSTORE8:
|
||
|
require(2)
|
||
|
off := stack.Pop()
|
||
|
val := stack.Pop()
|
||
|
|
||
|
mem.store[off.Int64()] = byte(val.Int64() & 0xff)
|
||
|
|
||
|
self.Printf(" => [%v] 0x%x", off, val)
|
||
|
case SLOAD:
|
||
|
require(1)
|
||
|
loc := stack.Pop()
|
||
10 years ago
|
val := ethutil.BigD(state.GetState(closure.Address(), loc.Bytes()))
|
||
|
stack.Push(val)
|
||
10 years ago
|
|
||
|
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
|
||
|
case SSTORE:
|
||
|
require(2)
|
||
|
val, loc := stack.Popn()
|
||
10 years ago
|
state.SetState(closure.Address(), loc.Bytes(), val)
|
||
10 years ago
|
|
||
10 years ago
|
// Debug sessions are allowed to run without message
|
||
|
if closure.message != nil {
|
||
|
closure.message.AddStorageChange(loc.Bytes())
|
||
|
}
|
||
10 years ago
|
|
||
|
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
|
||
|
case JUMP:
|
||
|
require(1)
|
||
10 years ago
|
|
||
10 years ago
|
jump(stack.Pop())
|
||
10 years ago
|
|
||
|
continue
|
||
|
case JUMPI:
|
||
|
require(2)
|
||
|
cond, pos := stack.Popn()
|
||
|
|
||
10 years ago
|
if cond.Cmp(ethutil.BigTrue) >= 0 {
|
||
|
jump(pos)
|
||
10 years ago
|
|
||
|
continue
|
||
|
}
|
||
10 years ago
|
|
||
10 years ago
|
case JUMPDEST:
|
||
|
case PC:
|
||
|
stack.Push(pc)
|
||
|
case MSIZE:
|
||
|
stack.Push(big.NewInt(int64(mem.Len())))
|
||
|
case GAS:
|
||
|
stack.Push(closure.Gas)
|
||
|
// 0x60 range
|
||
|
case CREATE:
|
||
|
require(3)
|
||
|
|
||
|
var (
|
||
|
err error
|
||
|
value = stack.Pop()
|
||
|
size, offset = stack.Popn()
|
||
|
input = mem.Get(offset.Int64(), size.Int64())
|
||
|
gas = new(big.Int).Set(closure.Gas)
|
||
|
|
||
|
// Snapshot the current stack so we are able to
|
||
|
// revert back to it later.
|
||
|
//snapshot = self.env.State().Copy()
|
||
|
)
|
||
|
|
||
|
// Generate a new address
|
||
10 years ago
|
n := state.GetNonce(closure.Address())
|
||
|
addr := ethcrypto.CreateAddress(closure.Address(), n)
|
||
|
state.SetNonce(closure.Address(), n+1)
|
||
10 years ago
|
|
||
|
self.Printf(" (*) %x", addr).Endl()
|
||
|
|
||
|
closure.UseGas(closure.Gas)
|
||
|
|
||
|
msg := NewExecution(self, addr, input, gas, closure.Price, value)
|
||
10 years ago
|
ret, err := msg.Create(closure)
|
||
10 years ago
|
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
|
||
|
|
||
|
stack.Push(ethutil.BigD(addr))
|
||
|
}
|
||
|
|
||
|
self.Endl()
|
||
|
|
||
|
// Debug hook
|
||
|
if self.Dbg != nil {
|
||
|
self.Dbg.SetCode(closure.Code)
|
||
|
}
|
||
|
case CALL, CALLCODE:
|
||
|
require(7)
|
||
|
|
||
|
self.Endl()
|
||
|
|
||
|
gas := stack.Pop()
|
||
|
// Pop gas and value of the stack.
|
||
|
value, addr := stack.Popn()
|
||
|
// Pop input size and offset
|
||
|
inSize, inOffset := stack.Popn()
|
||
|
// Pop return size and offset
|
||
|
retSize, retOffset := stack.Popn()
|
||
|
|
||
|
// Get the arguments from the memory
|
||
|
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
||
|
|
||
|
var executeAddr []byte
|
||
|
if op == CALLCODE {
|
||
|
executeAddr = closure.Address()
|
||
|
} else {
|
||
|
executeAddr = addr.Bytes()
|
||
|
}
|
||
|
|
||
|
msg := NewExecution(self, executeAddr, args, gas, closure.Price, value)
|
||
|
ret, err := msg.Exec(addr.Bytes(), closure)
|
||
|
if err != nil {
|
||
|
stack.Push(ethutil.BigFalse)
|
||
|
|
||
10 years ago
|
vmlogger.Debugln(err)
|
||
10 years ago
|
} else {
|
||
|
stack.Push(ethutil.BigTrue)
|
||
|
|
||
|
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
||
|
}
|
||
10 years ago
|
self.Printf("resume %x", closure.Address())
|
||
10 years ago
|
|
||
|
// Debug hook
|
||
|
if self.Dbg != nil {
|
||
|
self.Dbg.SetCode(closure.Code)
|
||
|
}
|
||
|
|
||
|
case RETURN:
|
||
|
require(2)
|
||
|
size, offset := stack.Popn()
|
||
|
ret := mem.Get(offset.Int64(), size.Int64())
|
||
|
|
||
|
self.Printf(" => (%d) 0x%x", len(ret), ret).Endl()
|
||
|
|
||
|
return closure.Return(ret), nil
|
||
|
case SUICIDE:
|
||
|
require(1)
|
||
|
|
||
10 years ago
|
receiver := state.GetOrNewStateObject(stack.Pop().Bytes())
|
||
10 years ago
|
|
||
10 years ago
|
receiver.AddAmount(state.GetBalance(closure.Address()))
|
||
|
state.Delete(closure.Address())
|
||
10 years ago
|
|
||
|
fallthrough
|
||
|
case STOP: // Stop the closure
|
||
|
self.Endl()
|
||
|
|
||
|
return closure.Return(nil), nil
|
||
|
default:
|
||
|
vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op)
|
||
|
|
||
|
//panic(fmt.Sprintf("Invalid opcode %x", op))
|
||
10 years ago
|
closure.ReturnGas(big.NewInt(1), nil)
|
||
10 years ago
|
|
||
|
return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op)
|
||
|
}
|
||
|
|
||
|
pc.Add(pc, ethutil.Big1)
|
||
|
|
||
|
self.Endl()
|
||
|
|
||
|
if self.Dbg != nil {
|
||
|
for _, instrNo := range self.Dbg.BreakPoints() {
|
||
|
if pc.Cmp(big.NewInt(instrNo)) == 0 {
|
||
|
self.Stepping = true
|
||
|
|
||
10 years ago
|
if !self.Dbg.BreakHook(prevStep, op, mem, stack, state.GetStateObject(closure.Address())) {
|
||
10 years ago
|
return nil, nil
|
||
|
}
|
||
|
} else if self.Stepping {
|
||
10 years ago
|
if !self.Dbg.StepHook(prevStep, op, mem, stack, state.GetStateObject(closure.Address())) {
|
||
10 years ago
|
return nil, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
10 years ago
|
func (self *DebugVm) Printf(format string, v ...interface{}) VirtualMachine {
|
||
10 years ago
|
if self.logTy == LogTyPretty {
|
||
|
self.logStr += fmt.Sprintf(format, v...)
|
||
|
}
|
||
|
|
||
|
return self
|
||
|
}
|
||
|
|
||
10 years ago
|
func (self *DebugVm) Endl() VirtualMachine {
|
||
10 years ago
|
if self.logTy == LogTyPretty {
|
||
|
vmlogger.Debugln(self.logStr)
|
||
|
self.logStr = ""
|
||
|
}
|
||
|
|
||
|
return self
|
||
|
}
|
||
|
|
||
|
func (self *DebugVm) Env() Environment {
|
||
|
return self.env
|
||
|
}
|
||
|
|
||
|
func (self *DebugVm) Depth() int {
|
||
|
return self.depth
|
||
|
}
|