|
|
|
package ethutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math/big"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Op codes
|
|
|
|
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,
|
|
|
|
"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
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
|
|
|
return num.Bytes(), nil
|
|
|
|
case int:
|
|
|
|
return big.NewInt(int64(s.(int))).Bytes(), nil
|
|
|
|
case []byte:
|
|
|
|
return BigD(s.([]byte)).Bytes(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func Instr(instr string) (int, []string, error) {
|
|
|
|
|
|
|
|
base := new(big.Int)
|
|
|
|
base.SetString(instr, 0)
|
|
|
|
|
|
|
|
args := make([]string, 7)
|
|
|
|
for i := 0; i < 7; i++ {
|
|
|
|
// int(int(val) / int(math.Pow(256,float64(i)))) % 256
|
|
|
|
exp := BigPow(256, i)
|
|
|
|
num := new(big.Int)
|
|
|
|
num.Div(base, exp)
|
|
|
|
|
|
|
|
args[i] = num.Mod(num, big.NewInt(256)).String()
|
|
|
|
}
|
|
|
|
op, _ := strconv.Atoi(args[0])
|
|
|
|
|
|
|
|
return op, args[1:7], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Script compilation functions
|
|
|
|
// Compiles strings to machine code
|
|
|
|
func Assemble(instructions ...interface{}) (script []string) {
|
|
|
|
script = make([]string, len(instructions))
|
|
|
|
|
|
|
|
for i, val := range instructions {
|
|
|
|
instr, _ := CompileInstr(val)
|
|
|
|
|
|
|
|
script[i] = string(instr)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|