Rewrote opcodes again

This commit is contained in:
obscuren 2014-03-20 22:51:20 +01:00
parent c68ff9886b
commit f3d27bf5d8
4 changed files with 217 additions and 245 deletions

View File

@ -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
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
// TODO FIX OPCODES // 0x10 range - bit ops
oCALL = 0x40 oAND = 0x10
oRETURN = 0x41 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 // 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",
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",
// 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", 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 { func (m *Memory) Set(offset, size int64, value []byte) {
return &ValueStack{} totSize := offset + size
} lenSize := int64(len(m.store))
if totSize > lenSize {
func (st *ValueStack) Pop() *ethutil.Value { // Calculate the diff between the sizes
s := len(st.data) diff := totSize - lenSize
if diff > 0 {
str := st.data[s-1] // Create a new empty slice and append it
st.data = st.data[:s-1] newSlice := make([]byte, diff+1)
// Resize slice
return str m.store = append(m.store, newSlice...)
}
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)
} }
} 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]
} }

View File

@ -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,
}) })
*/
} }

View File

@ -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)

View File

@ -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,
"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,
// TODO FIX OPCODES // 0x10 range - bit ops
"CALL": 0x40, "AND": 0x10,
"RETURN": 0x41, "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 { func IsOpCode(s string) bool {