Moved assembler stage processing to it's own file

This commit is contained in:
obscuren 2014-04-15 16:16:38 -04:00
parent 086acd122b
commit ca13e3b105
5 changed files with 430 additions and 213 deletions

126
ethchain/asm.go Normal file
View File

@ -0,0 +1,126 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"regexp"
)
func CompileInstr(s interface{}) ([]byte, error) {
switch s.(type) {
case string:
str := s.(string)
isOp := IsOpCode(str)
if isOp {
return []byte{OpCodes[str]}, nil
}
num := new(big.Int)
_, success := num.SetString(str, 0)
// Assume regular bytes during compilation
if !success {
num.SetBytes([]byte(str))
} else {
// tmp fix for 32 bytes
n := ethutil.BigToBytes(num, 256)
return n, nil
}
return num.Bytes(), nil
case int:
num := ethutil.BigToBytes(big.NewInt(int64(s.(int))), 256)
return num, nil
case []byte:
return ethutil.BigD(s.([]byte)).Bytes(), nil
}
return nil, nil
}
// Script compilation functions
// Compiles strings to machine code
func Assemble(instructions ...interface{}) (script []byte) {
//script = make([]string, len(instructions))
for _, val := range instructions {
instr, _ := CompileInstr(val)
//script[i] = string(instr)
script = append(script, instr...)
}
return
}
func Disassemble(script []byte) (asm []string) {
pc := new(big.Int)
for {
if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
return
}
// Get the memory location of pc
val := script[pc.Int64()]
// Get the opcode (it must be an opcode!)
op := OpCode(val)
asm = append(asm, fmt.Sprintf("%v", op))
switch op {
case oPUSH: // Push PC+1 on to the stack
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+32]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(31))
case oPUSH20:
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+20]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(19))
}
pc.Add(pc, ethutil.Big1)
}
return
}
func PreProcess(data string) (mainInput, initInput string) {
reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}"
mainReg := regexp.MustCompile("main" + reg)
initReg := regexp.MustCompile("init" + reg)
main := mainReg.FindStringSubmatch(data)
if len(main) > 0 {
mainInput = main[1]
} else {
mainInput = data
}
init := initReg.FindStringSubmatch(data)
if len(init) > 0 {
initInput = init[1]
}
return
}

View File

@ -71,7 +71,7 @@ func (c *Closure) Address() []byte {
type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack)
func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) {
c.Args = args c.Args = args
return vm.RunClosure(c, hook) return vm.RunClosure(c, hook)

View File

@ -6,153 +6,6 @@ import (
"math/big" "math/big"
) )
type OpCode int
// Op codes
const (
// 0x0 range - arithmetic ops
oSTOP = 0x00
oADD = 0x01
oMUL = 0x02
oSUB = 0x03
oDIV = 0x04
oSDIV = 0x05
oMOD = 0x06
oSMOD = 0x07
oEXP = 0x08
oNEG = 0x09
oLT = 0x0a
oGT = 0x0b
oEQ = 0x0c
oNOT = 0x0d
// 0x10 range - bit ops
oAND = 0x10
oOR = 0x11
oXOR = 0x12
oBYTE = 0x13
// 0x20 range - crypto
oSHA3 = 0x20
// 0x30 range - closure state
oADDRESS = 0x30
oBALANCE = 0x31
oORIGIN = 0x32
oCALLER = 0x33
oCALLVALUE = 0x34
oCALLDATA = 0x35
oCALLDATASIZE = 0x36
oGASPRICE = 0x37
// 0x40 range - block operations
oPREVHASH = 0x40
oCOINBASE = 0x41
oTIMESTAMP = 0x42
oNUMBER = 0x43
oDIFFICULTY = 0x44
oGASLIMIT = 0x45
// 0x50 range - 'storage' and execution
oPUSH = 0x50
oPUSH20 = 0x80
oPOP = 0x51
oDUP = 0x52
oSWAP = 0x53
oMLOAD = 0x54
oMSTORE = 0x55
oMSTORE8 = 0x56
oSLOAD = 0x57
oSSTORE = 0x58
oJUMP = 0x59
oJUMPI = 0x5a
oPC = 0x5b
oMSIZE = 0x5c
// 0x60 range - closures
oCREATE = 0x60
oCALL = 0x61
oRETURN = 0x62
// 0x70 range - other
oLOG = 0x70 // XXX Unofficial
oSUICIDE = 0x7f
)
// Since the opcodes aren't all in order we can't use a regular slice
var opCodeToString = map[OpCode]string{
// 0x0 range - arithmetic ops
oSTOP: "STOP",
oADD: "ADD",
oMUL: "MUL",
oSUB: "SUB",
oDIV: "DIV",
oSDIV: "SDIV",
oMOD: "MOD",
oSMOD: "SMOD",
oEXP: "EXP",
oNEG: "NEG",
oLT: "LT",
oGT: "GT",
oEQ: "EQ",
oNOT: "NOT",
// 0x10 range - bit ops
oAND: "AND",
oOR: "OR",
oXOR: "XOR",
oBYTE: "BYTE",
// 0x20 range - crypto
oSHA3: "SHA3",
// 0x30 range - closure state
oADDRESS: "ADDRESS",
oBALANCE: "BALANCE",
oORIGIN: "ORIGIN",
oCALLER: "CALLER",
oCALLVALUE: "CALLVALUE",
oCALLDATA: "CALLDATA",
oCALLDATASIZE: "CALLDATASIZE",
oGASPRICE: "TXGASPRICE",
// 0x40 range - block operations
oPREVHASH: "PREVHASH",
oCOINBASE: "COINBASE",
oTIMESTAMP: "TIMESTAMP",
oNUMBER: "NUMBER",
oDIFFICULTY: "DIFFICULTY",
oGASLIMIT: "GASLIMIT",
// 0x50 range - 'storage' and execution
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
oMSTORE: "MSTORE",
oMSTORE8: "MSTORE8",
oSLOAD: "SLOAD",
oSSTORE: "SSTORE",
oJUMP: "JUMP",
oJUMPI: "JUMPI",
oPC: "PC",
oMSIZE: "MSIZE",
// 0x60 range - closures
oCREATE: "CREATE",
oCALL: "CALL",
oRETURN: "RETURN",
// 0x70 range - other
oLOG: "LOG",
oSUICIDE: "SUICIDE",
}
func (o OpCode) String() string {
return opCodeToString[o]
}
type OpType int type OpType int
const ( const (
@ -177,6 +30,10 @@ func (st *Stack) Data() []*big.Int {
return st.data return st.data
} }
func (st *Stack) Len() int {
return len(st.data)
}
func (st *Stack) Pop() *big.Int { func (st *Stack) Pop() *big.Int {
str := st.data[len(st.data)-1] str := st.data[len(st.data)-1]

230
ethchain/types.go Normal file
View File

@ -0,0 +1,230 @@
package ethchain
type OpCode int
// Op codes
const (
// 0x0 range - arithmetic ops
oSTOP = 0x00
oADD = 0x01
oMUL = 0x02
oSUB = 0x03
oDIV = 0x04
oSDIV = 0x05
oMOD = 0x06
oSMOD = 0x07
oEXP = 0x08
oNEG = 0x09
oLT = 0x0a
oGT = 0x0b
oEQ = 0x0c
oNOT = 0x0d
// 0x10 range - bit ops
oAND = 0x10
oOR = 0x11
oXOR = 0x12
oBYTE = 0x13
// 0x20 range - crypto
oSHA3 = 0x20
// 0x30 range - closure state
oADDRESS = 0x30
oBALANCE = 0x31
oORIGIN = 0x32
oCALLER = 0x33
oCALLVALUE = 0x34
oCALLDATA = 0x35
oCALLDATASIZE = 0x36
oGASPRICE = 0x37
// 0x40 range - block operations
oPREVHASH = 0x40
oCOINBASE = 0x41
oTIMESTAMP = 0x42
oNUMBER = 0x43
oDIFFICULTY = 0x44
oGASLIMIT = 0x45
// 0x50 range - 'storage' and execution
oPUSH = 0x50
oPUSH20 = 0x80
oPOP = 0x51
oDUP = 0x52
oSWAP = 0x53
oMLOAD = 0x54
oMSTORE = 0x55
oMSTORE8 = 0x56
oSLOAD = 0x57
oSSTORE = 0x58
oJUMP = 0x59
oJUMPI = 0x5a
oPC = 0x5b
oMSIZE = 0x5c
// 0x60 range - closures
oCREATE = 0x60
oCALL = 0x61
oRETURN = 0x62
// 0x70 range - other
oLOG = 0x70 // XXX Unofficial
oSUICIDE = 0x7f
)
// Since the opcodes aren't all in order we can't use a regular slice
var opCodeToString = map[OpCode]string{
// 0x0 range - arithmetic ops
oSTOP: "STOP",
oADD: "ADD",
oMUL: "MUL",
oSUB: "SUB",
oDIV: "DIV",
oSDIV: "SDIV",
oMOD: "MOD",
oSMOD: "SMOD",
oEXP: "EXP",
oNEG: "NEG",
oLT: "LT",
oGT: "GT",
oEQ: "EQ",
oNOT: "NOT",
// 0x10 range - bit ops
oAND: "AND",
oOR: "OR",
oXOR: "XOR",
oBYTE: "BYTE",
// 0x20 range - crypto
oSHA3: "SHA3",
// 0x30 range - closure state
oADDRESS: "ADDRESS",
oBALANCE: "BALANCE",
oORIGIN: "ORIGIN",
oCALLER: "CALLER",
oCALLVALUE: "CALLVALUE",
oCALLDATA: "CALLDATA",
oCALLDATASIZE: "CALLDATASIZE",
oGASPRICE: "TXGASPRICE",
// 0x40 range - block operations
oPREVHASH: "PREVHASH",
oCOINBASE: "COINBASE",
oTIMESTAMP: "TIMESTAMP",
oNUMBER: "NUMBER",
oDIFFICULTY: "DIFFICULTY",
oGASLIMIT: "GASLIMIT",
// 0x50 range - 'storage' and execution
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
oMSTORE: "MSTORE",
oMSTORE8: "MSTORE8",
oSLOAD: "SLOAD",
oSSTORE: "SSTORE",
oJUMP: "JUMP",
oJUMPI: "JUMPI",
oPC: "PC",
oMSIZE: "MSIZE",
// 0x60 range - closures
oCREATE: "CREATE",
oCALL: "CALL",
oRETURN: "RETURN",
// 0x70 range - other
oLOG: "LOG",
oSUICIDE: "SUICIDE",
}
func (o OpCode) String() string {
return opCodeToString[o]
}
// Op codes for assembling
var OpCodes = map[string]byte{
// 0x0 range - arithmetic ops
"STOP": 0x00,
"ADD": 0x01,
"MUL": 0x02,
"SUB": 0x03,
"DIV": 0x04,
"SDIV": 0x05,
"MOD": 0x06,
"SMOD": 0x07,
"EXP": 0x08,
"NEG": 0x09,
"LT": 0x0a,
"GT": 0x0b,
"EQ": 0x0c,
"NOT": 0x0d,
// 0x10 range - bit ops
"AND": 0x10,
"OR": 0x11,
"XOR": 0x12,
"BYTE": 0x13,
// 0x20 range - crypto
"SHA3": 0x20,
// 0x30 range - closure state
"ADDRESS": 0x30,
"BALANCE": 0x31,
"ORIGIN": 0x32,
"CALLER": 0x33,
"CALLVALUE": 0x34,
"CALLDATA": 0x35,
"CALLDATASIZE": 0x36,
"GASPRICE": 0x38,
// 0x40 range - block operations
"PREVHASH": 0x40,
"COINBASE": 0x41,
"TIMESTAMP": 0x42,
"NUMBER": 0x43,
"DIFFICULTY": 0x44,
"GASLIMIT": 0x45,
// 0x50 range - 'storage' and execution
"PUSH": 0x50,
"PUSH20": 0x80,
"POP": 0x51,
"DUP": 0x52,
"SWAP": 0x53,
"MLOAD": 0x54,
"MSTORE": 0x55,
"MSTORE8": 0x56,
"SLOAD": 0x57,
"SSTORE": 0x58,
"JUMP": 0x59,
"JUMPI": 0x5a,
"PC": 0x5b,
"MSIZE": 0x5c,
// 0x60 range - closures
"CREATE": 0x60,
"CALL": 0x61,
"RETURN": 0x62,
// 0x70 range - other
"LOG": 0x70,
"SUICIDE": 0x7f,
}
func IsOpCode(s string) bool {
for key, _ := range OpCodes {
if key == s {
return true
}
}
return false
}

View File

@ -48,7 +48,19 @@ func NewVm(state *State, vars RuntimeVars) *Vm {
var Pow256 = ethutil.BigPow(2, 256) var Pow256 = ethutil.BigPow(2, 256)
func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { 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 {
fmt.Println(r)
ret = closure.Return(nil)
err = fmt.Errorf("%v", r)
}
}()
// If the amount of gas supplied is less equal to 0 // If the amount of gas supplied is less equal to 0
if closure.Gas.Cmp(big.NewInt(0)) <= 0 { if closure.Gas.Cmp(big.NewInt(0)) <= 0 {
// TODO Do something // TODO Do something
@ -58,6 +70,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
mem := &Memory{} mem := &Memory{}
// New stack (should this be shared?) // New stack (should this be shared?)
stack := NewStack() stack := NewStack()
require := func(m int) {
if stack.Len()-1 > m {
isRequireError = true
panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m))
}
}
// Instruction pointer // Instruction pointer
pc := big.NewInt(0) pc := big.NewInt(0)
// Current step count // Current step count
@ -121,7 +140,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
if closure.Gas.Cmp(gas) < 0 { if closure.Gas.Cmp(gas) < 0 {
ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas)
return closure.Return(nil) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas)
} }
switch op { switch op {
@ -129,10 +148,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Print() stack.Print()
mem.Print() mem.Print()
case oSTOP: // Stop the closure case oSTOP: // Stop the closure
return closure.Return(nil) return closure.Return(nil), nil
// 0x20 range // 0x20 range
case oADD: case oADD:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// (x + y) % 2 ** 256 // (x + y) % 2 ** 256
base.Add(x, y) base.Add(x, y)
@ -140,6 +160,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// Pop result back on the stack // Pop result back on the stack
stack.Push(base) stack.Push(base)
case oSUB: case oSUB:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// (x - y) % 2 ** 256 // (x - y) % 2 ** 256
base.Sub(x, y) base.Sub(x, y)
@ -147,6 +168,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// Pop result back on the stack // Pop result back on the stack
stack.Push(base) stack.Push(base)
case oMUL: case oMUL:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// (x * y) % 2 ** 256 // (x * y) % 2 ** 256
base.Mul(x, y) base.Mul(x, y)
@ -154,12 +176,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// Pop result back on the stack // Pop result back on the stack
stack.Push(base) stack.Push(base)
case oDIV: case oDIV:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// floor(x / y) // floor(x / y)
base.Div(x, y) base.Div(x, y)
// Pop result back on the stack // Pop result back on the stack
stack.Push(base) stack.Push(base)
case oSDIV: case oSDIV:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// n > 2**255 // n > 2**255
if x.Cmp(Pow256) > 0 { if x.Cmp(Pow256) > 0 {
@ -176,10 +200,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// Push result on to the stack // Push result on to the stack
stack.Push(z) stack.Push(z)
case oMOD: case oMOD:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
base.Mod(x, y) base.Mod(x, y)
stack.Push(base) stack.Push(base)
case oSMOD: case oSMOD:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// n > 2**255 // n > 2**255
if x.Cmp(Pow256) > 0 { if x.Cmp(Pow256) > 0 {
@ -196,14 +222,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// Push result on to the stack // Push result on to the stack
stack.Push(z) stack.Push(z)
case oEXP: case oEXP:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
base.Exp(x, y, Pow256) base.Exp(x, y, Pow256)
stack.Push(base) stack.Push(base)
case oNEG: case oNEG:
require(1)
base.Sub(Pow256, stack.Pop()) base.Sub(Pow256, stack.Pop())
stack.Push(base) stack.Push(base)
case oLT: case oLT:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// x < y // x < y
if x.Cmp(y) < 0 { if x.Cmp(y) < 0 {
@ -212,6 +241,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(ethutil.BigFalse) stack.Push(ethutil.BigFalse)
} }
case oGT: case oGT:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// x > y // x > y
if x.Cmp(y) > 0 { if x.Cmp(y) > 0 {
@ -220,6 +250,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(ethutil.BigFalse) stack.Push(ethutil.BigFalse)
} }
case oEQ: case oEQ:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
// x == y // x == y
if x.Cmp(y) == 0 { if x.Cmp(y) == 0 {
@ -228,6 +259,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(ethutil.BigFalse) stack.Push(ethutil.BigFalse)
} }
case oNOT: case oNOT:
require(1)
x := stack.Pop() x := stack.Pop()
if x.Cmp(ethutil.BigFalse) == 0 { if x.Cmp(ethutil.BigFalse) == 0 {
stack.Push(ethutil.BigTrue) stack.Push(ethutil.BigTrue)
@ -235,8 +267,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(ethutil.BigFalse) stack.Push(ethutil.BigFalse)
} }
// 0x10 range // 0x10 range
case oAND: case oAND:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) {
stack.Push(ethutil.BigTrue) stack.Push(ethutil.BigTrue)
@ -245,6 +278,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
} }
case oOR: case oOR:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) {
stack.Push(ethutil.BigTrue) stack.Push(ethutil.BigTrue)
@ -252,9 +286,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(ethutil.BigFalse) stack.Push(ethutil.BigFalse)
} }
case oXOR: case oXOR:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
stack.Push(base.Xor(x, y)) stack.Push(base.Xor(x, y))
case oBYTE: case oBYTE:
require(2)
val, th := stack.Popn() val, th := stack.Popn()
if th.Cmp(big.NewInt(32)) < 0 { if th.Cmp(big.NewInt(32)) < 0 {
stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64()))
@ -262,13 +298,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(ethutil.BigFalse) stack.Push(ethutil.BigFalse)
} }
// 0x20 range // 0x20 range
case oSHA3: case oSHA3:
require(2)
size, offset := stack.Popn() size, offset := stack.Popn()
data := mem.Get(offset.Int64(), size.Int64()) data := mem.Get(offset.Int64(), size.Int64())
stack.Push(ethutil.BigD(data)) stack.Push(ethutil.BigD(data))
// 0x30 range // 0x30 range
case oADDRESS: case oADDRESS:
stack.Push(ethutil.BigD(closure.Object().Address())) stack.Push(ethutil.BigD(closure.Object().Address()))
case oBALANCE: case oBALANCE:
@ -281,6 +318,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// FIXME: Original value of the call, not the current value // FIXME: Original value of the call, not the current value
stack.Push(closure.Value) stack.Push(closure.Value)
case oCALLDATA: case oCALLDATA:
require(1)
offset := stack.Pop() offset := stack.Pop()
mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args)
case oCALLDATASIZE: case oCALLDATASIZE:
@ -288,7 +326,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
case oGASPRICE: case oGASPRICE:
// TODO // TODO
// 0x40 range // 0x40 range
case oPREVHASH: case oPREVHASH:
stack.Push(ethutil.BigD(vm.vars.PrevHash)) stack.Push(ethutil.BigD(vm.vars.PrevHash))
case oCOINBASE: case oCOINBASE:
@ -300,7 +338,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
case oDIFFICULTY: case oDIFFICULTY:
stack.Push(vm.vars.Diff) stack.Push(vm.vars.Diff)
case oGASLIMIT: case oGASLIMIT:
// TODO // TODO
// 0x50 range // 0x50 range
case oPUSH: // Push PC+1 on to the stack case oPUSH: // Push PC+1 on to the stack
@ -324,34 +362,44 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
pc.Add(pc, big.NewInt(19)) pc.Add(pc, big.NewInt(19))
step++ step++
case oPOP: case oPOP:
require(1)
stack.Pop() stack.Pop()
case oDUP: case oDUP:
require(1)
stack.Push(stack.Peek()) stack.Push(stack.Peek())
case oSWAP: case oSWAP:
require(2)
x, y := stack.Popn() x, y := stack.Popn()
stack.Push(y) stack.Push(y)
stack.Push(x) stack.Push(x)
case oMLOAD: case oMLOAD:
require(1)
offset := stack.Pop() offset := stack.Pop()
stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32)))
case oMSTORE: // Store the value at stack top-1 in to memory at location stack top case oMSTORE: // Store the value at stack top-1 in to memory at location stack top
require(2)
// Pop value of the stack // Pop value of the stack
val, mStart := stack.Popn() val, mStart := stack.Popn()
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
case oMSTORE8: case oMSTORE8:
require(2)
val, mStart := stack.Popn() val, mStart := stack.Popn()
base.And(val, new(big.Int).SetInt64(0xff)) base.And(val, new(big.Int).SetInt64(0xff))
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
case oSLOAD: case oSLOAD:
require(1)
loc := stack.Pop() loc := stack.Pop()
val := closure.GetMem(loc) val := closure.GetMem(loc)
stack.Push(val.BigInt()) stack.Push(val.BigInt())
case oSSTORE: case oSSTORE:
require(2)
val, loc := stack.Popn() val, loc := stack.Popn()
closure.SetMem(loc, ethutil.NewValue(val)) closure.SetMem(loc, ethutil.NewValue(val))
case oJUMP: case oJUMP:
require(1)
pc = stack.Pop() pc = stack.Pop()
case oJUMPI: case oJUMPI:
require(2)
cond, pos := stack.Popn() cond, pos := stack.Popn()
if cond.Cmp(ethutil.BigTrue) == 0 { if cond.Cmp(ethutil.BigTrue) == 0 {
pc = pos pc = pos
@ -360,8 +408,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
stack.Push(pc) stack.Push(pc)
case oMSIZE: case oMSIZE:
stack.Push(big.NewInt(int64(mem.Len()))) stack.Push(big.NewInt(int64(mem.Len())))
// 0x60 range // 0x60 range
case oCREATE:
case oCALL: case oCALL:
require(8)
// Closure addr // Closure addr
addr := stack.Pop() addr := stack.Pop()
// Pop gas and value of the stack. // Pop gas and value of the stack.
@ -377,14 +427,20 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
// Create a new callable closure // Create a new callable closure
closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) closure := NewClosure(closure, contract, contract.script, vm.state, gas, value)
// Executer the closure and get the return value (if any) // Executer the closure and get the return value (if any)
ret := closure.Call(vm, args, hook) ret, err := closure.Call(vm, args, hook)
if err != nil {
stack.Push(ethutil.BigFalse)
} else {
stack.Push(ethutil.BigTrue)
}
mem.Set(retOffset.Int64(), retSize.Int64(), ret) mem.Set(retOffset.Int64(), retSize.Int64(), ret)
case oRETURN: case oRETURN:
require(2)
size, offset := stack.Popn() size, offset := stack.Popn()
ret := mem.Get(offset.Int64(), size.Int64()) ret := mem.Get(offset.Int64(), size.Int64())
return closure.Return(ret) return closure.Return(ret), nil
case oSUICIDE: case oSUICIDE:
/* /*
recAddr := stack.Pop().Bytes() recAddr := stack.Pop().Bytes()
@ -405,7 +461,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
default: default:
ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) ethutil.Config.Log.Debugf("Invalid opcode %x\n", op)
return closure.Return(nil) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op)
} }
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)
@ -415,55 +471,3 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte {
} }
} }
} }
func Disassemble(script []byte) (asm []string) {
pc := new(big.Int)
for {
if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
return
}
// Get the memory location of pc
val := script[pc.Int64()]
// Get the opcode (it must be an opcode!)
op := OpCode(val)
asm = append(asm, fmt.Sprintf("%v", op))
switch op {
case oPUSH: // Push PC+1 on to the stack
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+32]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(31))
case oPUSH20:
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+20]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(19))
}
pc.Add(pc, ethutil.Big1)
}
return
}