Rewrote opcodes again

pull/150/head
obscuren 11 years ago
parent c68ff9886b
commit f3d27bf5d8
  1. 303
      ethchain/stack.go
  2. 3
      ethchain/state_manager.go
  3. 41
      ethchain/vm.go
  4. 119
      ethutil/parsing.go

@ -2,7 +2,7 @@ package ethchain
import ( import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethutil" _ "github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
) )
@ -10,116 +10,136 @@ type OpCode int
// Op codes // Op codes
const ( const (
oSTOP = 0x00 // 0x0 range - arithmetic ops
oADD = 0x01 oSTOP = 0x00
oMUL = 0x02 oADD = 0x01
oSUB = 0x03 oMUL = 0x02
oDIV = 0x04 oSUB = 0x03
oSDIV = 0x05 oDIV = 0x04
oMOD = 0x06 oSDIV = 0x05
oSMOD = 0x07 oMOD = 0x06
oEXP = 0x08 oSMOD = 0x07
oNEG = 0x09 oEXP = 0x08
oLT = 0x0a oNEG = 0x09
oLE = 0x0b oLT = 0x0a
oGT = 0x0c oGT = 0x0b
oGE = 0x0d oEQ = 0x0c
oEQ = 0x0e oNOT = 0x0d
oNOT = 0x0f
oMYADDRESS = 0x10 // 0x10 range - bit ops
oTXSENDER = 0x11 oAND = 0x10
oTXVALUE = 0x12 oOR = 0x11
oTXDATAN = 0x13 oXOR = 0x12
oTXDATA = 0x14 oBYTE = 0x13
oBLK_PREVHASH = 0x15
oBLK_COINBASE = 0x16 // 0x20 range - crypto
oBLK_TIMESTAMP = 0x17 oSHA3 = 0x20
oBLK_NUMBER = 0x18
oBLK_DIFFICULTY = 0x19 // 0x30 range - closure state
oBLK_NONCE = 0x1a oADDRESS = 0x30
oBASEFEE = 0x1b oBALANCE = 0x31
oSHA256 = 0x20 oORIGIN = 0x32
oRIPEMD160 = 0x21 oCALLER = 0x33
oECMUL = 0x22 oCALLVALUE = 0x34
oECADD = 0x23 oCALLDATA = 0x35
oECSIGN = 0x24 oCALLDATASIZE = 0x36
oECRECOVER = 0x25 oRETURNDATASIZE = 0x37
oECVALID = 0x26 oTXGASPRICE = 0x38
oSHA3 = 0x27
oPUSH = 0x30 // 0x40 range - block operations
oPOP = 0x31 oPREVHASH = 0x40
oDUP = 0x32 oPREVNONCE = 0x41
oSWAP = 0x33 oCOINBASE = 0x42
oMLOAD = 0x34 oTIMESTAMP = 0x43
oMSTORE = 0x35 oNUMBER = 0x44
oSLOAD = 0x36 oDIFFICULTY = 0x45
oSSTORE = 0x37 oGASLIMIT = 0x46
oJMP = 0x38
oJMPI = 0x39 // 0x50 range - 'storage' and execution
oIND = 0x3a oPUSH = 0x50
oEXTRO = 0x3b oPOP = 0x51
oBALANCE = 0x3c oDUP = 0x52
oMKTX = 0x3d oSWAP = 0x53
oSUICIDE = 0x3f oMLOAD = 0x54
oMSTORE = 0x55
// TODO FIX OPCODES oMSTORE8 = 0x56
oCALL = 0x40 oSLOAD = 0x57
oRETURN = 0x41 oSSTORE = 0x58
oJUMP = 0x59
oJUMPI = 0x5a
oPC = 0x5b
oMEMSIZE = 0x5c
// 0x60 range - closures
oCREATE = 0x60
oCALL = 0x61
oRETURN = 0x62
) )
// Since the opcodes aren't all in order we can't use a regular slice // Since the opcodes aren't all in order we can't use a regular slice
var opCodeToString = map[OpCode]string{ var opCodeToString = map[OpCode]string{
oSTOP: "STOP", // 0x0 range - arithmetic ops
oADD: "ADD", oSTOP: "STOP",
oMUL: "MUL", oADD: "ADD",
oSUB: "SUB", oMUL: "MUL",
oDIV: "DIV", oSUB: "SUB",
oSDIV: "SDIV", oDIV: "DIV",
oMOD: "MOD", oSDIV: "SDIV",
oSMOD: "SMOD", oMOD: "MOD",
oEXP: "EXP", oSMOD: "SMOD",
oNEG: "NEG", oEXP: "EXP",
oLT: "LT", oNEG: "NEG",
oLE: "LE", oLT: "LT",
oGT: "GT", oGT: "GT",
oGE: "GE", oEQ: "EQ",
oEQ: "EQ", oNOT: "NOT",
oNOT: "NOT",
oMYADDRESS: "MYADDRESS", // 0x10 range - bit ops
oTXSENDER: "TXSENDER", oAND: "AND",
oTXVALUE: "TXVALUE", oOR: "OR",
oTXDATAN: "TXDATAN", oXOR: "XOR",
oTXDATA: "TXDATA", oBYTE: "BYTE",
oBLK_PREVHASH: "BLK_PREVHASH",
oBLK_COINBASE: "BLK_COINBASE", // 0x20 range - crypto
oBLK_TIMESTAMP: "BLK_TIMESTAMP", oSHA3: "SHA3",
oBLK_NUMBER: "BLK_NUMBER",
oBLK_DIFFICULTY: "BLK_DIFFICULTY", // 0x30 range - closure state
oBASEFEE: "BASEFEE", oADDRESS: "ADDRESS",
oSHA256: "SHA256",
oRIPEMD160: "RIPEMD160",
oECMUL: "ECMUL",
oECADD: "ECADD",
oECSIGN: "ECSIGN",
oECRECOVER: "ECRECOVER",
oECVALID: "ECVALID",
oSHA3: "SHA3",
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
oMSTORE: "MSTORE",
oSLOAD: "SLOAD",
oSSTORE: "SSTORE",
oJMP: "JMP",
oJMPI: "JMPI",
oIND: "IND",
oEXTRO: "EXTRO",
oBALANCE: "BALANCE", oBALANCE: "BALANCE",
oMKTX: "MKTX", oORIGIN: "ORIGIN",
oSUICIDE: "SUICIDE", oCALLER: "CALLER",
oCALLVALUE: "CALLVALUE",
oCALLDATA: "CALLDATA",
oCALLDATASIZE: "CALLDATASIZE",
oRETURNDATASIZE: "RETURNDATASIZE",
oTXGASPRICE: "TXGASPRICE",
// 0x40 range - block operations
oPREVHASH: "PREVHASH",
oPREVNONCE: "PREVNONCE",
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",
oMEMSIZE: "MEMSIZE",
// 0x60 range - closures
oCREATE: "CREATE",
oCALL: "CALL", oCALL: "CALL",
oRETURN: "RETURN", oRETURN: "RETURN",
} }
@ -189,61 +209,26 @@ func (st *Stack) Print() {
fmt.Println("#############") fmt.Println("#############")
} }
////////////// TODO this will eventually become the main stack once the big ints are removed from the VM type Memory struct {
type ValueStack struct { store []byte
data []*ethutil.Value
}
func NewValueStack() *ValueStack {
return &ValueStack{}
}
func (st *ValueStack) Pop() *ethutil.Value {
s := len(st.data)
str := st.data[s-1]
st.data = st.data[:s-1]
return str
}
func (st *ValueStack) Popn() (*ethutil.Value, *ethutil.Value) {
s := len(st.data)
ints := st.data[s-2:]
st.data = st.data[:s-2]
return ints[0], ints[1]
}
func (st *ValueStack) Peek() *ethutil.Value {
s := len(st.data)
str := st.data[s-1]
return str
} }
func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { func (m *Memory) Set(offset, size int64, value []byte) {
s := len(st.data) totSize := offset + size
lenSize := int64(len(m.store))
ints := st.data[s-2:] if totSize > lenSize {
// Calculate the diff between the sizes
return ints[0], ints[1] diff := totSize - lenSize
} if diff > 0 {
// Create a new empty slice and append it
func (st *ValueStack) Push(d *ethutil.Value) { newSlice := make([]byte, diff+1)
st.data = append(st.data, d) // Resize slice
} m.store = append(m.store, newSlice...)
func (st *ValueStack) Print() {
fmt.Println("### STACK ###")
if len(st.data) > 0 {
for i, val := range st.data {
fmt.Printf("%-3d %v\n", i, val)
} }
} else {
fmt.Println("-- empty --")
} }
fmt.Println("#############") copy(m.store[offset:offset+size+1], value)
}
func (m *Memory) Get(offset, size int64) []byte {
return m.store[offset : offset+size]
} }

@ -306,8 +306,8 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
}() }()
*/ */
/*TODO to be fixed and replaced by the new vm
vm := &Vm{} vm := &Vm{}
//vm.Process(contract, block.state, RuntimeVars{
vm.Process(contract, sm.procState, RuntimeVars{ vm.Process(contract, sm.procState, RuntimeVars{
address: tx.Hash()[12:], address: tx.Hash()[12:],
blockNumber: block.BlockInfo().Number, blockNumber: block.BlockInfo().Number,
@ -319,4 +319,5 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
txValue: tx.Value, txValue: tx.Value,
txData: tx.Data, txData: tx.Data,
}) })
*/
} }

@ -1,12 +1,12 @@
package ethchain package ethchain
import ( import (
"bytes" _ "bytes"
"fmt" "fmt"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go" _ "github.com/obscuren/secp256k1-go"
"log" "log"
"math" _ "math"
"math/big" "math/big"
) )
@ -45,7 +45,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
} }
// Memory for the current closure // Memory for the current closure
var mem []byte mem := &Memory{}
// New stack (should this be shared?) // New stack (should this be shared?)
stack := NewStack() stack := NewStack()
// Instruction pointer // Instruction pointer
@ -86,19 +86,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
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
// Pop value of the stack // Pop value of the stack
val, mStart := stack.Popn() val, mStart := stack.Popn()
// Ensure that memory is large enough to hold the data mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
// If it isn't resize the memory slice so that it may hold the value
bytesLen := big.NewInt(32)
totSize := new(big.Int).Add(mStart, bytesLen)
lenSize := big.NewInt(int64(len(mem)))
if totSize.Cmp(lenSize) > 0 {
// Calculate the diff between the sizes
diff := new(big.Int).Sub(totSize, lenSize)
// Create a new empty slice and append it
newSlice := make([]byte, diff.Int64()+1)
mem = append(mem, newSlice...)
}
copy(mem[mStart.Int64():mStart.Int64()+bytesLen.Int64()+1], ethutil.BigToBytes(val, 256))
case oCALL: case oCALL:
// Pop return size and offset // Pop return size and offset
retSize, retOffset := stack.Popn() retSize, retOffset := stack.Popn()
@ -116,23 +104,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
closure := NewClosure(closure, contract, vm.state, gas, value) closure := NewClosure(closure, contract, 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, nil) ret := closure.Call(vm, nil)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
// Ensure that memory is large enough to hold the returned data
// If it isn't resize the memory slice so that it may hold the value
totSize := new(big.Int).Add(retOffset, retSize)
lenSize := big.NewInt(int64(len(mem)))
if totSize.Cmp(lenSize) > 0 {
// Calculate the diff between the sizes
diff := new(big.Int).Sub(totSize, lenSize)
// Create a new empty slice and append it
newSlice := make([]byte, diff.Int64()+1)
mem = append(mem, newSlice...)
}
// Copy over the returned values to the memory given the offset and size
copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret)
case oRETURN: case oRETURN:
size, offset := stack.Popn() size, offset := stack.Popn()
ret := mem[offset.Int64() : offset.Int64()+size.Int64()+1] ret := mem.Get(offset.Int64(), size.Int64())
return closure.Return(ret) return closure.Return(ret)
} }
@ -141,6 +116,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
} }
} }
/*
// Old VM code // Old VM code
func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) {
vm.mem = make(map[string]*big.Int) vm.mem = make(map[string]*big.Int)
@ -507,6 +483,7 @@ out:
state.UpdateContract(addr, contract) state.UpdateContract(addr, contract)
} }
*/
func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) {
ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length)

@ -7,61 +7,70 @@ import (
// Op codes // Op codes
var OpCodes = map[string]byte{ var OpCodes = map[string]byte{
"STOP": 0x00, // 0x0 range - arithmetic ops
"ADD": 0x01, "STOP": 0x00,
"MUL": 0x02, "ADD": 0x01,
"SUB": 0x03, "MUL": 0x02,
"DIV": 0x04, "SUB": 0x03,
"SDIV": 0x05, "DIV": 0x04,
"MOD": 0x06, "SDIV": 0x05,
"SMOD": 0x07, "MOD": 0x06,
"EXP": 0x08, "SMOD": 0x07,
"NEG": 0x09, "EXP": 0x08,
"LT": 0x0a, "NEG": 0x09,
"LE": 0x0b, "LT": 0x0a,
"GT": 0x0c, "GT": 0x0b,
"GE": 0x0d, "EQ": 0x0c,
"EQ": 0x0e, "NOT": 0x0d,
"NOT": 0x0f,
"MYADDRESS": 0x10, // 0x10 range - bit ops
"TXSENDER": 0x11, "AND": 0x10,
"TXVALUE": 0x12, "OR": 0x11,
"TXDATAN": 0x13, "XOR": 0x12,
"TXDATA": 0x14, "BYTE": 0x13,
"BLK_PREVHASH": 0x15,
"BLK_COINBASE": 0x16, // 0x20 range - crypto
"BLK_TIMESTAMP": 0x17, "SHA3": 0x20,
"BLK_NUMBER": 0x18,
"BLK_DIFFICULTY": 0x19, // 0x30 range - closure state
"BLK_NONCE": 0x1a, "ADDRESS": 0x30,
"BASEFEE": 0x1b, "BALANCE": 0x31,
"SHA256": 0x20, "ORIGIN": 0x32,
"RIPEMD160": 0x21, "CALLER": 0x33,
"ECMUL": 0x22, "CALLVALUE": 0x34,
"ECADD": 0x23, "CALLDATA": 0x35,
"ECSIGN": 0x24, "CALLDATASIZE": 0x36,
"ECRECOVER": 0x25, "RETURNDATASIZE": 0x37,
"ECVALID": 0x26, "TXGASPRICE": 0x38,
"SHA3": 0x27,
"PUSH": 0x30, // 0x40 range - block operations
"POP": 0x31, "PREVHASH": 0x40,
"DUP": 0x32, "PREVNONCE": 0x41,
"SWAP": 0x33, "COINBASE": 0x42,
"MLOAD": 0x34, "TIMESTAMP": 0x43,
"MSTORE": 0x35, "NUMBER": 0x44,
"SLOAD": 0x36, "DIFFICULTY": 0x45,
"SSTORE": 0x37, "GASLIMIT": 0x46,
"JMP": 0x38,
"JMPI": 0x39, // 0x50 range - 'storage' and execution
"IND": 0x3a, "PUSH": 0x50,
"EXTRO": 0x3b, "POP": 0x51,
"BALANCE": 0x3c, "DUP": 0x52,
"MKTX": 0x3d, "SWAP": 0x53,
"SUICIDE": 0x3f, "MLOAD": 0x54,
"MSTORE": 0x55,
// TODO FIX OPCODES "MSTORE8": 0x56,
"CALL": 0x40, "SLOAD": 0x57,
"RETURN": 0x41, "SSTORE": 0x58,
"JUMP": 0x59,
"JUMPI": 0x5a,
"PC": 0x5b,
"MEMSIZE": 0x5c,
// 0x60 range - closures
"CREATE": 0x60,
"CALL": 0x61,
"RETURN": 0x62,
} }
func IsOpCode(s string) bool { func IsOpCode(s string) bool {

Loading…
Cancel
Save