aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-04-16 04:16:38 +0800
committerobscuren <geffobscura@gmail.com>2014-04-16 04:16:38 +0800
commitca13e3b1058f0d680b79dc1d9319d427a09493f8 (patch)
treea121191d4e43ecc41878d268f46739e121fc111b /ethchain
parent086acd122b59071255b0c1cfae569748b1d7427a (diff)
downloadgo-tangerine-ca13e3b1058f0d680b79dc1d9319d427a09493f8.tar.gz
go-tangerine-ca13e3b1058f0d680b79dc1d9319d427a09493f8.tar.zst
go-tangerine-ca13e3b1058f0d680b79dc1d9319d427a09493f8.zip
Moved assembler stage processing to it's own file
Diffstat (limited to 'ethchain')
-rw-r--r--ethchain/asm.go126
-rw-r--r--ethchain/closure.go2
-rw-r--r--ethchain/stack.go151
-rw-r--r--ethchain/types.go230
-rw-r--r--ethchain/vm.go134
5 files changed, 430 insertions, 213 deletions
diff --git a/ethchain/asm.go b/ethchain/asm.go
new file mode 100644
index 000000000..5f901f8a2
--- /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 0fbe48f92..0762e8f49 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 2aca0a350..288360062 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 000000000..24aad82c3
--- /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 b88cd2861..33d667457 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
-}