From f3d27bf5d878120346f8cdd0744e7f1f8e1ee631 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 22:51:20 +0100 Subject: [PATCH] Rewrote opcodes again --- ethchain/stack.go | 301 ++++++++++++++++++-------------------- ethchain/state_manager.go | 3 +- ethchain/vm.go | 41 ++---- ethutil/parsing.go | 117 ++++++++------- 4 files changed, 217 insertions(+), 245 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index bfb19614e..429c31d08 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,7 +2,7 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" + _ "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -10,116 +10,136 @@ type OpCode int // Op codes const ( - oSTOP = 0x00 - oADD = 0x01 - oMUL = 0x02 - oSUB = 0x03 - oDIV = 0x04 - oSDIV = 0x05 - oMOD = 0x06 - oSMOD = 0x07 - oEXP = 0x08 - oNEG = 0x09 - oLT = 0x0a - oLE = 0x0b - oGT = 0x0c - oGE = 0x0d - oEQ = 0x0e - oNOT = 0x0f - oMYADDRESS = 0x10 - oTXSENDER = 0x11 - oTXVALUE = 0x12 - oTXDATAN = 0x13 - oTXDATA = 0x14 - oBLK_PREVHASH = 0x15 - oBLK_COINBASE = 0x16 - oBLK_TIMESTAMP = 0x17 - oBLK_NUMBER = 0x18 - oBLK_DIFFICULTY = 0x19 - oBLK_NONCE = 0x1a - oBASEFEE = 0x1b - oSHA256 = 0x20 - oRIPEMD160 = 0x21 - oECMUL = 0x22 - oECADD = 0x23 - oECSIGN = 0x24 - oECRECOVER = 0x25 - oECVALID = 0x26 - oSHA3 = 0x27 - oPUSH = 0x30 - oPOP = 0x31 - oDUP = 0x32 - oSWAP = 0x33 - oMLOAD = 0x34 - oMSTORE = 0x35 - oSLOAD = 0x36 - oSSTORE = 0x37 - oJMP = 0x38 - oJMPI = 0x39 - oIND = 0x3a - oEXTRO = 0x3b - oBALANCE = 0x3c - oMKTX = 0x3d - oSUICIDE = 0x3f + // 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 - // TODO FIX OPCODES - oCALL = 0x40 - oRETURN = 0x41 + // 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 + oRETURNDATASIZE = 0x37 + oTXGASPRICE = 0x38 + + // 0x40 range - block operations + oPREVHASH = 0x40 + oPREVNONCE = 0x41 + oCOINBASE = 0x42 + oTIMESTAMP = 0x43 + oNUMBER = 0x44 + oDIFFICULTY = 0x45 + oGASLIMIT = 0x46 + + // 0x50 range - 'storage' and execution + oPUSH = 0x50 + oPOP = 0x51 + oDUP = 0x52 + oSWAP = 0x53 + oMLOAD = 0x54 + oMSTORE = 0x55 + oMSTORE8 = 0x56 + oSLOAD = 0x57 + 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 var opCodeToString = map[OpCode]string{ - oSTOP: "STOP", - oADD: "ADD", - oMUL: "MUL", - oSUB: "SUB", - oDIV: "DIV", - oSDIV: "SDIV", - oMOD: "MOD", - oSMOD: "SMOD", - oEXP: "EXP", - oNEG: "NEG", - oLT: "LT", - oLE: "LE", - oGT: "GT", - oGE: "GE", - oEQ: "EQ", - oNOT: "NOT", - oMYADDRESS: "MYADDRESS", - oTXSENDER: "TXSENDER", - oTXVALUE: "TXVALUE", - oTXDATAN: "TXDATAN", - oTXDATA: "TXDATA", - oBLK_PREVHASH: "BLK_PREVHASH", - oBLK_COINBASE: "BLK_COINBASE", - oBLK_TIMESTAMP: "BLK_TIMESTAMP", - oBLK_NUMBER: "BLK_NUMBER", - oBLK_DIFFICULTY: "BLK_DIFFICULTY", - oBASEFEE: "BASEFEE", - 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", - oMKTX: "MKTX", - oSUICIDE: "SUICIDE", + // 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", + 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", oRETURN: "RETURN", } @@ -189,61 +209,26 @@ func (st *Stack) Print() { fmt.Println("#############") } -////////////// TODO this will eventually become the main stack once the big ints are removed from the VM -type ValueStack struct { - data []*ethutil.Value +type Memory struct { + store []byte } -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) { - s := len(st.data) - - ints := st.data[s-2:] - - return ints[0], ints[1] -} - -func (st *ValueStack) Push(d *ethutil.Value) { - st.data = append(st.data, d) -} - -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) +func (m *Memory) Set(offset, size int64, value []byte) { + totSize := offset + size + lenSize := int64(len(m.store)) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff+1) + // Resize slice + m.store = append(m.store, newSlice...) } - } 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] } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e67f0f680..14686b217 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -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.Process(contract, block.state, RuntimeVars{ vm.Process(contract, sm.procState, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, @@ -319,4 +319,5 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo txValue: tx.Value, txData: tx.Data, }) + */ } diff --git a/ethchain/vm.go b/ethchain/vm.go index 2fa78a748..6479409f8 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -1,12 +1,12 @@ package ethchain import ( - "bytes" + _ "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/secp256k1-go" + _ "github.com/obscuren/secp256k1-go" "log" - "math" + _ "math" "math/big" ) @@ -45,7 +45,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } // Memory for the current closure - var mem []byte + mem := &Memory{} // New stack (should this be shared?) stack := NewStack() // 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 // Pop value of the stack val, mStart := stack.Popn() - // Ensure that memory is large enough to hold the data - // 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)) + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() @@ -116,23 +104,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, nil) - - // 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) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: size, offset := stack.Popn() - ret := mem[offset.Int64() : offset.Int64()+size.Int64()+1] + ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret) } @@ -141,6 +116,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } +/* // Old VM code func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { vm.mem = make(map[string]*big.Int) @@ -507,6 +483,7 @@ out: state.UpdateContract(addr, contract) } +*/ 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) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 459cdc284..9ff2827a0 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -7,61 +7,70 @@ import ( // Op codes var OpCodes = map[string]byte{ - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "LE": 0x0b, - "GT": 0x0c, - "GE": 0x0d, - "EQ": 0x0e, - "NOT": 0x0f, - "MYADDRESS": 0x10, - "TXSENDER": 0x11, - "TXVALUE": 0x12, - "TXDATAN": 0x13, - "TXDATA": 0x14, - "BLK_PREVHASH": 0x15, - "BLK_COINBASE": 0x16, - "BLK_TIMESTAMP": 0x17, - "BLK_NUMBER": 0x18, - "BLK_DIFFICULTY": 0x19, - "BLK_NONCE": 0x1a, - "BASEFEE": 0x1b, - "SHA256": 0x20, - "RIPEMD160": 0x21, - "ECMUL": 0x22, - "ECADD": 0x23, - "ECSIGN": 0x24, - "ECRECOVER": 0x25, - "ECVALID": 0x26, - "SHA3": 0x27, - "PUSH": 0x30, - "POP": 0x31, - "DUP": 0x32, - "SWAP": 0x33, - "MLOAD": 0x34, - "MSTORE": 0x35, - "SLOAD": 0x36, - "SSTORE": 0x37, - "JMP": 0x38, - "JMPI": 0x39, - "IND": 0x3a, - "EXTRO": 0x3b, - "BALANCE": 0x3c, - "MKTX": 0x3d, - "SUICIDE": 0x3f, + // 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, - // TODO FIX OPCODES - "CALL": 0x40, - "RETURN": 0x41, + // 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, + "RETURNDATASIZE": 0x37, + "TXGASPRICE": 0x38, + + // 0x40 range - block operations + "PREVHASH": 0x40, + "PREVNONCE": 0x41, + "COINBASE": 0x42, + "TIMESTAMP": 0x43, + "NUMBER": 0x44, + "DIFFICULTY": 0x45, + "GASLIMIT": 0x46, + + // 0x50 range - 'storage' and execution + "PUSH": 0x50, + "POP": 0x51, + "DUP": 0x52, + "SWAP": 0x53, + "MLOAD": 0x54, + "MSTORE": 0x55, + "MSTORE8": 0x56, + "SLOAD": 0x57, + "SSTORE": 0x58, + "JUMP": 0x59, + "JUMPI": 0x5a, + "PC": 0x5b, + "MEMSIZE": 0x5c, + + // 0x60 range - closures + "CREATE": 0x60, + "CALL": 0x61, + "RETURN": 0x62, } func IsOpCode(s string) bool {