diff options
-rw-r--r-- | ethchain/state_manager.go | 2 | ||||
-rw-r--r-- | ethchain/state_transition.go | 2 | ||||
-rw-r--r-- | ethchain/transaction.go | 5 | ||||
-rw-r--r-- | ethchain/transaction_pool.go | 2 | ||||
-rw-r--r-- | ethcrypto/crypto.go | 18 | ||||
-rw-r--r-- | ethcrypto/crypto_test.go | 17 | ||||
-rw-r--r-- | ethpipe/js_types.go | 34 | ||||
-rw-r--r-- | ethstate/state.go | 9 | ||||
-rw-r--r-- | ethstate/state_object.go | 6 | ||||
-rw-r--r-- | ethutil/list.go | 42 | ||||
-rw-r--r-- | ethvm/types.go | 49 | ||||
-rw-r--r-- | ethvm/vm.go | 62 |
12 files changed, 180 insertions, 68 deletions
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 08bd22d29..33af259cf 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -237,6 +237,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Add the block to the chain sm.bc.Add(block) + sm.transState = state.Copy() + // Create a bloom bin for this block filter := sm.createBloomFilter(state) // Persist the data diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1c7eae675..c1180a641 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -283,7 +283,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context for e := vm.Queue().Front(); e != nil; e = e.Next() { msg := e.Value.(*ethvm.Message) - msg.Exec(transactor) + msg.Exec(msg.Addr(), transactor) } } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e1b48a3d3..e7e8f3a9f 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,7 +13,8 @@ import ( var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} func IsContractAddr(addr []byte) bool { - return bytes.Compare(addr, ContractAddr) == 0 + return len(addr) == 0 + //return bytes.Compare(addr, ContractAddr) == 0 } type Transaction struct { @@ -31,7 +32,7 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index b0d62fd91..bd8b27a6d 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -72,8 +72,6 @@ type TxPool struct { func NewTxPool(ethereum EthManager) *TxPool { return &TxPool{ - //server: s, - mutex: sync.Mutex{}, pool: list.New(), queueChan: make(chan *Transaction, txPoolQueueSize), quit: make(chan bool), diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index 19f8c9e55..1f500f2db 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -1,25 +1,11 @@ package ethcrypto import ( - "code.google.com/p/go.crypto/ripemd160" - "code.google.com/p/go.crypto/sha3" - "crypto/sha256" + //"code.google.com/p/go.crypto/sha3" "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/sha3" ) -func Sha256Bin(data []byte) []byte { - hash := sha256.Sum256(data) - - return hash[:] -} - -func Ripemd160(data []byte) []byte { - ripemd := ripemd160.New() - ripemd.Write(data) - - return ripemd.Sum(nil) -} - func Sha3Bin(data []byte) []byte { d := sha3.NewKeccak256() d.Write(data) diff --git a/ethcrypto/crypto_test.go b/ethcrypto/crypto_test.go new file mode 100644 index 000000000..7323e1646 --- /dev/null +++ b/ethcrypto/crypto_test.go @@ -0,0 +1,17 @@ +package ethcrypto + +import ( + "bytes" + "testing" + + "github.com/ethereum/eth-go/ethutil" +) + +// FIPS 202 test (reverted back to FIPS 180) +func TestSha3(t *testing.T) { + const exp = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" + sha3_256 := Sha3Bin([]byte("abc")) + if bytes.Compare(sha3_256, ethutil.Hex2Bytes(exp)) != 0 { + t.Errorf("Sha3_256 failed. Incorrect result %x", sha3_256) + } +} diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go index d9cbef12d..8d2805f3d 100644 --- a/ethpipe/js_types.go +++ b/ethpipe/js_types.go @@ -1,7 +1,6 @@ package ethpipe import ( - "encoding/json" "strconv" "strings" @@ -13,16 +12,17 @@ import ( // Block interface exposed to QML type JSBlock struct { + //Transactions string `json:"transactions"` ref *ethchain.Block - Size string `json:"size"` - Number int `json:"number"` - Hash string `json:"hash"` - Transactions string `json:"transactions"` - Time int64 `json:"time"` - Coinbase string `json:"coinbase"` - Name string `json:"name"` - GasLimit string `json:"gasLimit"` - GasUsed string `json:"gasUsed"` + Size string `json:"size"` + Number int `json:"number"` + Hash string `json:"hash"` + Transactions *ethutil.List `json:"transactions"` + Time int64 `json:"time"` + Coinbase string `json:"coinbase"` + Name string `json:"name"` + GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` } // Creates a new QML Block from a chain block @@ -36,12 +36,16 @@ func NewJSBlock(block *ethchain.Block) *JSBlock { ptxs = append(ptxs, *NewJSTx(tx)) } - txJson, err := json.Marshal(ptxs) - if err != nil { - return nil - } + /* + txJson, err := json.Marshal(ptxs) + if err != nil { + return nil + } + return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} + */ + list := ethutil.NewList(ptxs) - return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} + return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: list, Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} } func (self *JSBlock) ToString() string { diff --git a/ethstate/state.go b/ethstate/state.go index 2f7f00a32..42bbf021b 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -49,6 +49,15 @@ func (self *State) GetNonce(addr []byte) uint64 { return 0 } +func (self *State) GetCode(addr []byte) []byte { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Code + } + + return nil +} + // // Setting, updating & deleting state object methods // diff --git a/ethstate/state_object.go b/ethstate/state_object.go index bf4e92583..6fc0696a8 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -297,8 +297,12 @@ func (c *StateObject) RlpEncode() []byte { } else { root = "" } + var codeHash []byte + if len(c.Code) > 0 { + codeHash = ethcrypto.Sha3Bin(c.Code) + } - return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, ethcrypto.Sha3Bin(c.Code)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, codeHash}) } func (c *StateObject) RlpDecode(data []byte) { diff --git a/ethutil/list.go b/ethutil/list.go new file mode 100644 index 000000000..18bf04792 --- /dev/null +++ b/ethutil/list.go @@ -0,0 +1,42 @@ +package ethutil + +import "reflect" + +// The list type is an anonymous slice handler which can be used +// for containing any slice type to use in an environment which +// does not support slice types (e.g., JavaScript, QML) +type List struct { + list reflect.Value + Length int +} + +// Initialise a new list. Panics if non-slice type is given. +func NewList(t interface{}) *List { + list := reflect.ValueOf(t) + if list.Kind() != reflect.Slice { + panic("list container initialized with a non-slice type") + } + + return &List{list, list.Len()} +} + +// Get N element from the embedded slice. Returns nil if OOB. +func (self *List) Get(i int) interface{} { + if self.list.Len() > i { + return self.list.Index(i).Interface() + } + + return nil +} + +// Appends value at the end of the slice. Panics when incompatible value +// is given. +func (self *List) Append(v interface{}) { + self.list = reflect.Append(self.list, reflect.ValueOf(v)) + self.Length = self.list.Len() +} + +// Returns the underlying slice as interface. +func (self *List) Interface() interface{} { + return self.list.Interface() +} diff --git a/ethvm/types.go b/ethvm/types.go index bb6735993..9cddd7c33 100644 --- a/ethvm/types.go +++ b/ethvm/types.go @@ -49,6 +49,8 @@ const ( CODESIZE = 0x38 CODECOPY = 0x39 GASPRICE = 0x3a + EXTCODECOPY = 0x3b + EXTCODESIZE = 0x3c // 0x40 range - block operations PREVHASH = 0x40 @@ -142,10 +144,11 @@ const ( SWAP16 = 0x9f // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 - POST = 0xf3 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + POST = 0xf3 + CALLSTATELESS = 0xf4 // 0x70 range - other LOG = 0xfe // XXX Unofficial @@ -197,12 +200,14 @@ var opCodeToString = map[OpCode]string{ GASPRICE: "TXGASPRICE", // 0x40 range - block operations - PREVHASH: "PREVHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", // 0x50 range - 'storage' and execution POP: "POP", @@ -288,9 +293,11 @@ var opCodeToString = map[OpCode]string{ SWAP16: "SWAP16", // 0xf0 range - CREATE: "CREATE", - CALL: "CALL", - RETURN: "RETURN", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + POST: "POST", + CALLSTATELESS: "CALLSTATELESS", // 0x70 range - other LOG: "LOG", @@ -343,7 +350,12 @@ var OpCodes = map[string]byte{ "CALLVALUE": 0x34, "CALLDATALOAD": 0x35, "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, + "CALLDATACOPY": 0x37, + "CODESIZE": 0x38, + "CODECOPY": 0x39, + "GASPRICE": 0x3a, + "EXTCODECOPY": 0x3b, + "EXTCODESIZE": 0x3c, // 0x40 range - block operations "PREVHASH": 0x40, @@ -436,10 +448,11 @@ var OpCodes = map[string]byte{ "SWAP16": 0x9f, // 0xf0 range - closures - "CREATE": 0xf0, - "CALL": 0xf1, - "RETURN": 0xf2, - "POST": 0xf3, + "CREATE": 0xf0, + "CALL": 0xf1, + "RETURN": 0xf2, + "POST": 0xf3, + "CALLSTATELESS": 0xf4, // 0x70 range - other "LOG": 0xfe, diff --git a/ethvm/vm.go b/ethvm/vm.go index 924a861ca..9518540e0 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -197,7 +197,11 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(3) newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() - case CALL: + case EXTCODECOPY: + require(4) + + newMemSize = stack.data[stack.Len()-1].Uint64() + stack.data[stack.Len()-4].Uint64() + case CALL, CALLSTATELESS: require(7) gas.Set(GasCall) addStepGasUsage(stack.data[stack.Len()-1]) @@ -550,14 +554,32 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { code := closure.Args[cOff : cOff+l] mem.Set(mOff, l, code) - case CODESIZE: - l := big.NewInt(int64(len(closure.Code))) + case CODESIZE, EXTCODESIZE: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = self.env.State().GetCode(addr) + } else { + code = closure.Code + } + + l := big.NewInt(int64(len(code))) stack.Push(l) self.Printf(" => %d", l) - case CODECOPY: + case CODECOPY, EXTCODECOPY: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = self.env.State().GetCode(addr) + } else { + code = closure.Code + } + var ( - size = int64(len(closure.Code)) + size = int64(len(code)) mOff = stack.Pop().Int64() cOff = stack.Pop().Int64() l = stack.Pop().Int64() @@ -570,9 +592,9 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { l = 0 } - code := closure.Code[cOff : cOff+l] + codeCopy := code[cOff : cOff+l] - mem.Set(mOff, l, code) + mem.Set(mOff, l, codeCopy) case GASPRICE: stack.Push(closure.Price) @@ -730,7 +752,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { closure.UseGas(closure.Gas) msg := NewMessage(self, addr, input, gas, closure.Price, value) - ret, err := msg.Exec(closure) + ret, err := msg.Exec(addr, closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -794,7 +816,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if self.Dbg != nil { self.Dbg.SetCode(closure.Code) } - case CALL: + case CALL, CALLSTATELESS: require(7) self.Endl() @@ -812,8 +834,15 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { snapshot := self.env.State().Copy() - msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value) - ret, err := msg.Exec(closure) + var executeAddr []byte + if op == CALLSTATELESS { + executeAddr = closure.Address() + } else { + executeAddr = addr.Bytes() + } + + msg := NewMessage(self, executeAddr, args, gas, closure.Price, value) + ret, err := msg.Exec(addr.Bytes(), closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -995,7 +1024,11 @@ func (self *Message) Postpone() { self.vm.queue.PushBack(self) } -func (self *Message) Exec(caller ClosureRef) (ret []byte, err error) { +func (self *Message) Addr() []byte { + return self.address +} + +func (self *Message) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err error) { queue := self.vm.queue self.vm.queue = list.New() @@ -1027,8 +1060,11 @@ func (self *Message) Exec(caller ClosureRef) (ret []byte, err error) { caller.Object().SubAmount(self.value) stateObject.AddAmount(self.value) + // Retrieve the executing code + code := self.vm.env.State().GetCode(codeAddr) + // Create a new callable closure - c := NewClosure(msg, caller, object, object.Code, self.gas, self.price) + c := NewClosure(msg, caller, object, code, self.gas, self.price) // Executer the closure and get the return value (if any) ret, _, err = c.Call(self.vm, self.input) |