aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ethchain/state_manager.go2
-rw-r--r--ethchain/state_transition.go2
-rw-r--r--ethchain/transaction.go5
-rw-r--r--ethchain/transaction_pool.go2
-rw-r--r--ethcrypto/crypto.go18
-rw-r--r--ethcrypto/crypto_test.go17
-rw-r--r--ethpipe/js_types.go34
-rw-r--r--ethstate/state.go9
-rw-r--r--ethstate/state_object.go6
-rw-r--r--ethutil/list.go42
-rw-r--r--ethvm/types.go49
-rw-r--r--ethvm/vm.go62
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)