Commit 97786d03 authored by Maran's avatar Maran

Merge branch 'master' into miner

parents 274d5cc9 6a86c517
......@@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof
of Concept 3". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
of Concept 3.5". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
Ethereum Go is split up in several sub packages Please refer to each
individual package for more information.
......
......@@ -6,23 +6,39 @@ import (
)
type Account struct {
address []byte
Amount *big.Int
Nonce uint64
}
func NewAccount(amount *big.Int) *Account {
return &Account{Amount: amount, Nonce: 0}
func NewAccount(address []byte, amount *big.Int) *Account {
return &Account{address, amount, 0}
}
func NewAccountFromData(data []byte) *Account {
address := &Account{}
address.RlpDecode(data)
func NewAccountFromData(address, data []byte) *Account {
account := &Account{address: address}
account.RlpDecode(data)
return address
return account
}
func (a *Account) AddFee(fee *big.Int) {
a.Amount.Add(a.Amount, fee)
a.AddFunds(fee)
}
func (a *Account) AddFunds(funds *big.Int) {
a.Amount.Add(a.Amount, funds)
}
func (a *Account) Address() []byte {
return a.address
}
// Implements Callee
func (a *Account) ReturnGas(value *big.Int, state *State) {
// Return the value back to the sender
a.AddFunds(value)
state.UpdateAccount(a.address, a)
}
func (a *Account) RlpEncode() []byte {
......
......@@ -142,7 +142,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
data := block.state.trie.Get(string(block.Coinbase))
// Get the ether (Coinbase) and add the fee (gief fee to miner)
ether := NewAccountFromData([]byte(data))
ether := NewAccountFromData(block.Coinbase, []byte(data))
base = new(big.Int)
ether.Amount = base.Add(ether.Amount, fee)
......
package ethchain
/*
import (
_ "fmt"
"github.com/ethereum/eth-go/ethdb"
......@@ -14,9 +15,10 @@ func TestVm(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
ethutil.Config.Db = db
bm := NewBlockManager(nil)
bm := NewStateManager(nil)
block := bm.bc.genesisBlock
bm.Prepare(block.State(), block.State())
script := Compile([]string{
"PUSH",
"1",
......@@ -31,3 +33,4 @@ func TestVm(t *testing.T) {
tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
bm.ApplyTransactions(block, []*Transaction{tx2})
}
*/
package ethchain
// TODO Re write VM to use values instead of big integers?
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type Callee interface {
ReturnGas(*big.Int, *State)
Address() []byte
}
type ClosureBody interface {
Callee
ethutil.RlpEncodable
GetMem(*big.Int) *ethutil.Value
SetMem(*big.Int, *ethutil.Value)
}
// Basic inline closure object which implement the 'closure' interface
type Closure struct {
callee Callee
object ClosureBody
State *State
Gas *big.Int
Value *big.Int
Args []byte
}
// Create a new closure for the given data items
func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure {
return &Closure{callee, object, state, gas, val, nil}
}
// Retuns the x element in data slice
func (c *Closure) GetMem(x *big.Int) *ethutil.Value {
m := c.object.GetMem(x)
if m == nil {
return ethutil.EmptyValue()
}
return m
}
func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) {
c.object.SetMem(x, val)
}
func (c *Closure) Address() []byte {
return c.object.Address()
}
func (c *Closure) Call(vm *Vm, args []byte) []byte {
c.Args = args
return vm.RunClosure(c)
}
func (c *Closure) Return(ret []byte) []byte {
// Return the remaining gas to the callee
// If no callee is present return it to
// the origin (i.e. contract or tx)
if c.callee != nil {
c.callee.ReturnGas(c.Gas, c.State)
} else {
c.object.ReturnGas(c.Gas, c.State)
// TODO incase it's a POST contract we gotta serialise the contract again.
// But it's not yet defined
}
return ret
}
// Implement the Callee interface
func (c *Closure) ReturnGas(gas *big.Int, state *State) {
// Return the gas to the closure
c.Gas.Add(c.Gas, gas)
}
func (c *Closure) Object() ClosureBody {
return c.object
}
func (c *Closure) Callee() Callee {
return c.callee
}
......@@ -10,25 +10,21 @@ type Contract struct {
Nonce uint64
//state *ethutil.Trie
state *State
address []byte
}
func NewContract(Amount *big.Int, root []byte) *Contract {
contract := &Contract{Amount: Amount, Nonce: 0}
func NewContract(address []byte, Amount *big.Int, root []byte) *Contract {
contract := &Contract{address: address, Amount: Amount, Nonce: 0}
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root)))
return contract
}
func (c *Contract) RlpEncode() []byte {
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root})
}
func NewContractFromBytes(address, data []byte) *Contract {
contract := &Contract{address: address}
contract.RlpDecode(data)
func (c *Contract) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
c.Amount = decoder.Get(0).BigInt()
c.Nonce = decoder.Get(1).Uint()
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
return contract
}
func (c *Contract) Addr(addr []byte) *ethutil.Value {
......@@ -43,19 +39,45 @@ func (c *Contract) State() *State {
return c.state
}
func (c *Contract) GetMem(num int) *ethutil.Value {
nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256)
func (c *Contract) GetMem(num *big.Int) *ethutil.Value {
nb := ethutil.BigToBytes(num, 256)
return c.Addr(nb)
}
func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) {
addr := ethutil.BigToBytes(num, 256)
c.state.trie.Update(string(addr), string(val.Encode()))
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *Contract) ReturnGas(val *big.Int, state *State) {
c.Amount.Add(c.Amount, val)
}
func (c *Contract) Address() []byte {
return c.address
}
func (c *Contract) RlpEncode() []byte {
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root})
}
func (c *Contract) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
c.Amount = decoder.Get(0).BigInt()
c.Nonce = decoder.Get(1).Uint()
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
}
func MakeContract(tx *Transaction, state *State) *Contract {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.Hash()[12:]
value := tx.Value
contract := NewContract(value, []byte(""))
contract := NewContract(addr, value, []byte(""))
state.trie.Update(string(addr), string(contract.RlpEncode()))
for i, val := range tx.Data {
if len(val) > 0 {
......
......@@ -2,6 +2,7 @@ package ethchain
import (
"fmt"
_ "github.com/ethereum/eth-go/ethutil"
"math/big"
)
......@@ -9,6 +10,7 @@ type OpCode int
// Op codes
const (
// 0x0 range - arithmetic ops
oSTOP = 0x00
oADD = 0x01
oMUL = 0x02
......@@ -20,50 +22,65 @@ const (
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
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
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",
......@@ -75,44 +92,59 @@ var opCodeToString = map[OpCode]string{
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",
// 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",
oJMP: "JMP",
oJMPI: "JMPI",
oIND: "IND",
oEXTRO: "EXTRO",
oBALANCE: "BALANCE",
oMKTX: "MKTX",
oJUMP: "JUMP",
oJUMPI: "JUMPI",
oPC: "PC",
oMSIZE: "MSIZE",
// 0x60 range - closures
oCREATE: "CREATE",
oCALL: "CALL",
oRETURN: "RETURN",
// 0x70 range - other
oLOG: "LOG",
oSUICIDE: "SUICIDE",
}
......@@ -141,35 +173,27 @@ func NewStack() *Stack {
}
func (st *Stack) Pop() *big.Int {
s := len(st.data)
str := st.data[s-1]
st.data = st.data[:s-1]
str := st.data[0]
st.data = st.data[1:]
return str
}
func (st *Stack) Popn() (*big.Int, *big.Int) {
s := len(st.data)
ints := st.data[s-2:]
st.data = st.data[:s-2]
ints := st.data[:2]
st.data = st.data[2:]
return ints[0], ints[1]
}
func (st *Stack) Peek() *big.Int {
s := len(st.data)
str := st.data[s-1]
str := st.data[0]
return str
}
func (st *Stack) Peekn() (*big.Int, *big.Int) {
s := len(st.data)
ints := st.data[s-2:]
ints := st.data[:2]
return ints[0], ints[1]
}
......@@ -188,3 +212,45 @@ func (st *Stack) Print() {
}
fmt.Println("#############")
}
type Memory struct {
store []byte
}
func (m *Memory) Set(offset, size int64, value []byte) {
totSize := offset + size
lenSize := int64(len(m.store) - 1)
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...)
}
}
copy(m.store[offset:offset+size], value)
}
func (m *Memory) Get(offset, size int64) []byte {
return m.store[offset : offset+size]
}
func (m *Memory) Len() int {
return len(m.store)
}
func (m *Memory) Print() {
fmt.Println("### MEM ###")
if len(m.store) > 0 {
addr := 0
for i := 0; i+32 < len(m.store); i += 32 {
fmt.Printf("%03d %v\n", addr, m.store[i:i+32])
addr++
}
} else {
fmt.Println("-- empty --")
}
fmt.Println("###########")
}
......@@ -63,8 +63,7 @@ func (s *State) GetContract(addr []byte) *Contract {
}
// build contract
contract := &Contract{}
contract.RlpDecode([]byte(data))
contract := NewContractFromBytes(addr, []byte(data))
// Check if there's a cached state for this contract
cachedState := s.states[string(addr)]
......@@ -78,27 +77,19 @@ func (s *State) GetContract(addr []byte) *Contract {
return contract
}
func (s *State) UpdateContract(addr []byte, contract *Contract) {
s.trie.Update(string(addr), string(contract.RlpEncode()))
}
func Compile(code []string) (script []string) {
script = make([]string, len(code))
for i, val := range code {
instr, _ := ethutil.CompileInstr(val)
script[i] = string(instr)
}
func (s *State) UpdateContract(contract *Contract) {
addr := contract.Address()
return
s.states[string(addr)] = contract.state
s.trie.Update(string(addr), string(contract.RlpEncode()))
}
func (s *State) GetAccount(addr []byte) (account *Account) {
data := s.trie.Get(string(addr))
if data == "" {
account = NewAccount(big.NewInt(0))
account = NewAccount(addr, big.NewInt(0))
} else {
account = NewAccountFromData([]byte(data))
account = NewAccountFromData(addr, []byte(data))
}
return
......@@ -153,3 +144,35 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) {
return val, typ
}
func (s *State) Put(key, object []byte) {
s.trie.Update(string(key), string(object))
}
func (s *State) Root() interface{} {
return s.trie.Root
}
// Script compilation functions
// Compiles strings to machine code
func Compile(code []string) (script []string) {
script = make([]string, len(code))
for i, val := range code {
instr, _ := ethutil.CompileInstr(val)
script[i] = string(instr)
}
return
}
func CompileToValues(code []string) (script []*ethutil.Value) {
script = make([]*ethutil.Value, len(code))
for i, val := range code {
instr, _ := ethutil.CompileInstr(val)
script[i] = ethutil.NewValue(instr)
}
return
}
......@@ -308,18 +308,17 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
}
}()
*/
vm := &Vm{}
//vm.Process(contract, block.state, RuntimeVars{
vm.Process(contract, sm.procState, RuntimeVars{
address: tx.Hash()[12:],
caller := sm.procState.GetAccount(tx.Sender())
closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value)
vm := NewVm(sm.procState, RuntimeVars{
origin: caller.Address(),
blockNumber: block.BlockInfo().Number,
sender: tx.Sender(),
prevHash: block.PrevHash,
coinbase: block.Coinbase,
time: block.Time,
diff: block.Difficulty,
txValue: tx.Value,
txData: tx.Data,
// XXX Tx data? Could be just an argument to the closure instead
txData: nil,
})
closure.Call(vm, nil)
}
......@@ -13,22 +13,31 @@ type Transaction struct {
Nonce uint64
Recipient []byte
Value *big.Int
Gas *big.Int
Gasprice *big.Int
Data []string
Memory []int
v byte
r, s []byte
}
func NewTransaction(to []byte, value *big.Int, data []string) *Transaction {
tx := Transaction{Recipient: to, Value: value}
tx.Nonce = 0
// Serialize the data
tx.Data = data
tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data}
return &tx
}
func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction {
return &Transaction{Value: value, Gasprice: gasprice, Data: data}
}
func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction {
return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data}
}
func NewTx(to []byte, value *big.Int, data []string) *Transaction {
return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data}
}
// XXX Deprecated
func NewTransactionFromData(data []byte) *Transaction {
return NewTransactionFromBytes(data)
......
This diff is collapsed.
package ethchain
import (
"fmt"
"bytes"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
/*
func TestRun(t *testing.T) {
InitFees()
......@@ -104,3 +106,69 @@ func TestRun2(t *testing.T) {
txData: tx.Data,
})
}
*/
// XXX Full stack test
func TestRun3(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"PUSH", "300",
"PUSH", "0",
"MSTORE",
"PUSH", "32",
"CALLDATA",
"PUSH", "64",
"PUSH", "0",
"RETURN",
})
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
addr := tx.Hash()[12:]
contract := MakeContract(tx, state)
state.UpdateContract(contract)
callerScript := ethutil.Compile(
"PUSH", 1337, // Argument
"PUSH", 65, // argument mem offset
"MSTORE",
"PUSH", 64, // ret size
"PUSH", 0, // ret offset
"PUSH", 32, // arg size
"PUSH", 65, // arg offset
"PUSH", 1000, /// Gas
"PUSH", 0, /// value
"PUSH", addr, // Sender
"CALL",
"PUSH", 64,
"PUSH", 0,
"RETURN",
)
callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript)
// Contract addr as test address
account := NewAccount(ContractAddr, big.NewInt(10000000))
callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int))
vm := NewVm(state, RuntimeVars{
origin: account.Address(),
blockNumber: 1,
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
// XXX Tx data? Could be just an argument to the closure instead
txData: nil,
})
ret := callerClosure.Call(vm, nil)
exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57}
if bytes.Compare(ret, exp) != 0 {
t.Errorf("expected return value to be %v, got %v", exp, ret)
}
}
......@@ -33,3 +33,9 @@ func CurrencyToString(num *big.Int) string {
return fmt.Sprintf("%v Wei", num)
}
var (
Big1 = big.NewInt(1)
Big0 = big.NewInt(0)
Big256 = big.NewInt(0xff)
)
......@@ -6,6 +6,7 @@ import (
"os"
"os/user"
"path"
"runtime"
)
type LogType byte
......@@ -23,6 +24,7 @@ type config struct {
ExecPath string
Debug bool
Ver string
ClientString string
Pubkey []byte
Seed bool
}
......@@ -48,11 +50,16 @@ func ReadConfig(base string) *config {
Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"}
Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug)
Config.SetClientString("/Ethereum(G)")
}
return Config
}
func (c *config) SetClientString(str string) {
Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS)
}
type LoggerType byte
const (
......
......@@ -7,6 +7,7 @@ import (
// Op codes
var OpCodes = map[string]byte{
// 0x0 range - arithmetic ops
"STOP": 0x00,
"ADD": 0x01,
"MUL": 0x02,
......@@ -18,46 +19,60 @@ var OpCodes = map[string]byte{
"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,
"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 {
......@@ -69,16 +84,30 @@ func IsOpCode(s string) bool {
return false
}
func CompileInstr(s string) ([]byte, error) {
isOp := IsOpCode(s)
func CompileInstr(s interface{}) ([]byte, error) {
switch s.(type) {
case string:
str := s.(string)
isOp := IsOpCode(str)
if isOp {
return []byte{OpCodes[s]}, nil
return []byte{OpCodes[str]}, nil
}
num := new(big.Int)
num.SetString(s, 0)
_, 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) {
......@@ -99,3 +128,17 @@ func Instr(instr string) (int, []string, error) {
return op, args[1:7], nil
}
// Script compilation functions
// Compiles strings to machine code
func Compile(instructions ...interface{}) (script []string) {
script = make([]string, len(instructions))
for i, val := range instructions {
instr, _ := CompileInstr(val)
script[i] = string(instr)
}
return
}
......@@ -9,6 +9,10 @@ import (
"math/big"
)
type RlpEncodable interface {
RlpEncode() []byte
}
type RlpEncoder struct {
rlpData []byte
}
......
package ethutil
import (
"fmt"
"reflect"
"testing"
)
......
......@@ -7,7 +7,6 @@ import (
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"net"
"runtime"
"strconv"
"strings"
"sync/atomic"
......@@ -160,7 +159,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
connected: 0,
disconnect: 0,
caps: caps,
Version: fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS),
Version: ethutil.Config.ClientString,
}
// Set up the connection in another goroutine so we don't block the main thread
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment