From ca13e3b1058f0d680b79dc1d9319d427a09493f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Apr 2014 16:16:38 -0400 Subject: [PATCH] Moved assembler stage processing to it's own file --- ethchain/asm.go | 126 ++++++++++++++++++++++++ ethchain/closure.go | 2 +- ethchain/stack.go | 151 +---------------------------- ethchain/types.go | 230 ++++++++++++++++++++++++++++++++++++++++++++ ethchain/vm.go | 134 +++++++++++++------------- 5 files changed, 430 insertions(+), 213 deletions(-) create mode 100644 ethchain/asm.go create mode 100644 ethchain/types.go diff --git a/ethchain/asm.go b/ethchain/asm.go new file mode 100644 index 0000000000..5f901f8a23 --- /dev/null +++ b/ethchain/asm.go @@ -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 +} diff --git a/ethchain/closure.go b/ethchain/closure.go index 0fbe48f921..0762e8f49f 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -71,7 +71,7 @@ func (c *Closure) Address() []byte { 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 return vm.RunClosure(c, hook) diff --git a/ethchain/stack.go b/ethchain/stack.go index 2aca0a3500..2883600627 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -6,153 +6,6 @@ import ( "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 const ( @@ -177,6 +30,10 @@ func (st *Stack) Data() []*big.Int { return st.data } +func (st *Stack) Len() int { + return len(st.data) +} + func (st *Stack) Pop() *big.Int { str := st.data[len(st.data)-1] diff --git a/ethchain/types.go b/ethchain/types.go new file mode 100644 index 0000000000..24aad82c37 --- /dev/null +++ b/ethchain/types.go @@ -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 +} diff --git a/ethchain/vm.go b/ethchain/vm.go index b88cd28613..33d667457e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,19 @@ func NewVm(state *State, vars RuntimeVars) *Vm { 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 closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -58,6 +70,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { mem := &Memory{} // New stack (should this be shared?) 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 pc := big.NewInt(0) // Current step count @@ -121,7 +140,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { if closure.Gas.Cmp(gas) < 0 { 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 { @@ -129,10 +148,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Print() mem.Print() case oSTOP: // Stop the closure - return closure.Return(nil) + return closure.Return(nil), nil - // 0x20 range + // 0x20 range case oADD: + require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) @@ -140,6 +160,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oSUB: + require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) @@ -147,6 +168,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oMUL: + require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) @@ -154,12 +176,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oDIV: + require(2) x, y := stack.Popn() // floor(x / y) base.Div(x, y) // Pop result back on the stack stack.Push(base) case oSDIV: + require(2) x, y := stack.Popn() // n > 2**255 if x.Cmp(Pow256) > 0 { @@ -176,10 +200,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Push result on to the stack stack.Push(z) case oMOD: + require(2) x, y := stack.Popn() base.Mod(x, y) stack.Push(base) case oSMOD: + require(2) x, y := stack.Popn() // n > 2**255 if x.Cmp(Pow256) > 0 { @@ -196,14 +222,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Push result on to the stack stack.Push(z) case oEXP: + require(2) x, y := stack.Popn() base.Exp(x, y, Pow256) stack.Push(base) case oNEG: + require(1) base.Sub(Pow256, stack.Pop()) stack.Push(base) case oLT: + require(2) x, y := stack.Popn() // x < y if x.Cmp(y) < 0 { @@ -212,6 +241,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oGT: + require(2) x, y := stack.Popn() // x > y if x.Cmp(y) > 0 { @@ -220,6 +250,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oEQ: + require(2) x, y := stack.Popn() // x == y if x.Cmp(y) == 0 { @@ -228,6 +259,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oNOT: + require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) == 0 { stack.Push(ethutil.BigTrue) @@ -235,8 +267,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } - // 0x10 range + // 0x10 range case oAND: + require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { stack.Push(ethutil.BigTrue) @@ -245,6 +278,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { } case oOR: + require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { stack.Push(ethutil.BigTrue) @@ -252,9 +286,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oXOR: + require(2) x, y := stack.Popn() stack.Push(base.Xor(x, y)) case oBYTE: + require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { 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) } - // 0x20 range + // 0x20 range case oSHA3: + require(2) size, offset := stack.Popn() data := mem.Get(offset.Int64(), size.Int64()) stack.Push(ethutil.BigD(data)) - // 0x30 range + // 0x30 range case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) 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 stack.Push(closure.Value) case oCALLDATA: + require(1) offset := stack.Pop() mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALLDATASIZE: @@ -288,7 +326,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oGASPRICE: // TODO - // 0x40 range + // 0x40 range case oPREVHASH: stack.Push(ethutil.BigD(vm.vars.PrevHash)) case oCOINBASE: @@ -300,7 +338,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oDIFFICULTY: stack.Push(vm.vars.Diff) case oGASLIMIT: - // TODO + // TODO // 0x50 range 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)) step++ case oPOP: + require(1) stack.Pop() case oDUP: + require(1) stack.Push(stack.Peek()) case oSWAP: + require(2) x, y := stack.Popn() stack.Push(y) stack.Push(x) case oMLOAD: + require(1) offset := stack.Pop() 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 + require(2) // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oMSTORE8: + require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: + require(1) loc := stack.Pop() val := closure.GetMem(loc) stack.Push(val.BigInt()) case oSSTORE: + require(2) val, loc := stack.Popn() closure.SetMem(loc, ethutil.NewValue(val)) case oJUMP: + require(1) pc = stack.Pop() case oJUMPI: + require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos @@ -360,8 +408,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(pc) case oMSIZE: stack.Push(big.NewInt(int64(mem.Len()))) - // 0x60 range + // 0x60 range + case oCREATE: case oCALL: + require(8) // Closure addr addr := stack.Pop() // 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 closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // 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) case oRETURN: + require(2) size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) - return closure.Return(ret) + return closure.Return(ret), nil case oSUICIDE: /* recAddr := stack.Pop().Bytes() @@ -405,7 +461,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { default: 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) @@ -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 -}