From f486c0ae563eaf89a601ca5d60f30be96db2e69a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 11:59:52 +0100 Subject: [PATCH 01/78] new type + additional methods --- common/bytes.go | 2 +- common/types.go | 36 +++++++++++++++++++++++++++++++ core/types/block.go | 34 ++++++++++++++--------------- state/managed_state.go | 25 ++++++++++++--------- state/state_object.go | 14 ++++++------ state/statedb.go | 49 +++++++++++++++++++++--------------------- trie/trie.go | 9 +++++--- 7 files changed, 107 insertions(+), 62 deletions(-) diff --git a/common/bytes.go b/common/bytes.go index 4aef9a223..5e553d23c 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -211,7 +211,7 @@ func RightPadString(str string, l int) string { } -func Address(slice []byte) (addr []byte) { +func ToAddress(slice []byte) (addr []byte) { if len(slice) < 20 { addr = LeftPadBytes(slice, 20) } else if len(slice) > 20 { diff --git a/common/types.go b/common/types.go index 7646b2c34..11ac39815 100644 --- a/common/types.go +++ b/common/types.go @@ -4,3 +4,39 @@ type ( Hash [32]byte Address [20]byte ) + +// Don't use the default 'String' method in case we want to overwrite + +// Get the string representation of the underlying hash +func (h Hash) Str() string { + return string(h[:]) +} + +// Sets the hash to the value of b. If b is larger than len(h) it will panic +func (h Hash) SetBytes(b []byte) { + if len(b) > len(h) { + panic("unable to set bytes. too big") + } + + // reverse loop + for i := len(b); i >= 0; i-- { + h[i] = b[i] + } +} + +// Get the string representation of the underlying address +func (a Address) Str() string { + return string(a[:]) +} + +// Sets the address to the value of b. If b is larger than len(a) it will panic +func (h Address) SetBytes(b []byte) { + if len(b) > len(h) { + panic("unable to set bytes. too big") + } + + // reverse loop + for i := len(b); i >= 0; i-- { + h[i] = b[i] + } +} diff --git a/core/types/block.go b/core/types/block.go index 2d65cdca6..fadf67086 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -8,26 +8,26 @@ import ( "sort" "time" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) type Header struct { // Hash to the previous block - ParentHash []byte + ParentHash common.Hash // Uncles of this block - UncleHash []byte + UncleHash common.Hash // The coin base address - Coinbase []byte + Coinbase common.Address // Block Trie state - Root []byte + Root common.Hash // Tx sha - TxHash []byte + TxHash common.Hash // Receipt sha - ReceiptHash []byte + ReceiptHash common.Hash // Bloom - Bloom []byte + Bloom [256]byte // Difficulty for the current block Difficulty *big.Int // The block number @@ -41,9 +41,9 @@ type Header struct { // Extra data Extra string // Mix digest for quick checking to prevent DOS - MixDigest []byte + MixDigest common.Hash // Nonce - Nonce []byte + Nonce [8]byte } func (self *Header) rlpData(withNonce bool) []interface{} { @@ -206,13 +206,13 @@ func (self *Block) SetNonce(nonce uint64) { self.header.setNonce(nonce) } -func (self *Block) Bloom() []byte { return self.header.Bloom } -func (self *Block) Coinbase() []byte { return self.header.Coinbase } -func (self *Block) Time() int64 { return int64(self.header.Time) } -func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } -func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } -func (self *Block) Root() []byte { return self.header.Root } -func (self *Block) SetRoot(root []byte) { self.header.Root = root } +func (self *Block) Bloom() []byte { return self.header.Bloom } +func (self *Block) Coinbase() []byte { return self.header.Coinbase } +func (self *Block) Time() int64 { return int64(self.header.Time) } +func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } +func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } +func (self *Block) Root() []byte { return self.header.Root } +func (self *Block) SetRoot(root []byte) { self.header.Root = root } func (self *Block) Size() common.StorageSize { return common.StorageSize(len(common.Encode(self))) } func (self *Block) GetTransaction(i int) *Transaction { if len(self.transactions) > i { diff --git a/state/managed_state.go b/state/managed_state.go index aff0206b2..0fcc1be67 100644 --- a/state/managed_state.go +++ b/state/managed_state.go @@ -1,6 +1,10 @@ package state -import "sync" +import ( + "sync" + + "github.com/ethereum/go-ethereum/common" +) type account struct { stateObject *StateObject @@ -29,7 +33,7 @@ func (ms *ManagedState) SetState(statedb *StateDB) { ms.StateDB = statedb } -func (ms *ManagedState) RemoveNonce(addr []byte, n uint64) { +func (ms *ManagedState) RemoveNonce(addr common.Address, n uint64) { if ms.hasAccount(addr) { ms.mu.Lock() defer ms.mu.Unlock() @@ -43,7 +47,7 @@ func (ms *ManagedState) RemoveNonce(addr []byte, n uint64) { } } -func (ms *ManagedState) NewNonce(addr []byte) uint64 { +func (ms *ManagedState) NewNonce(addr common.Address) uint64 { ms.mu.RLock() defer ms.mu.RUnlock() @@ -57,26 +61,27 @@ func (ms *ManagedState) NewNonce(addr []byte) uint64 { return uint64(len(account.nonces)) + account.nstart } -func (ms *ManagedState) hasAccount(addr []byte) bool { - _, ok := ms.accounts[string(addr)] +func (ms *ManagedState) hasAccount(addr common.Address) bool { + _, ok := ms.accounts[addr.Str()] return ok } -func (ms *ManagedState) getAccount(addr []byte) *account { - if account, ok := ms.accounts[string(addr)]; !ok { +func (ms *ManagedState) getAccount(addr common.Address) *account { + straddr := addr.Str() + if account, ok := ms.accounts[straddr]; !ok { so := ms.GetOrNewStateObject(addr) - ms.accounts[string(addr)] = newAccount(so) + ms.accounts[straddr] = newAccount(so) } else { // Always make sure the state account nonce isn't actually higher // than the tracked one. so := ms.StateDB.GetStateObject(addr) if so != nil && uint64(len(account.nonces))+account.nstart < so.nonce { - ms.accounts[string(addr)] = newAccount(so) + ms.accounts[straddr] = newAccount(so) } } - return ms.accounts[string(addr)] + return ms.accounts[straddr] } func newAccount(so *StateObject) *account { diff --git a/state/state_object.go b/state/state_object.go index 8be9e28fc..396577a75 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -5,8 +5,8 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -44,7 +44,7 @@ type StateObject struct { State *StateDB // Address belonging to this account - address []byte + address common.Address // The balance of the account balance *big.Int // The nonce of the account @@ -77,9 +77,9 @@ func (self *StateObject) Reset() { self.State.Reset() } -func NewStateObject(addr []byte, db common.Database) *StateObject { +func NewStateObject(address common.Address, db common.Database) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. - address := common.Address(addr) + //address := common.ToAddress(addr) object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int), dirty: true} object.State = New(nil, db) //New(trie.New(common.Config.Db, "")) @@ -90,12 +90,12 @@ func NewStateObject(addr []byte, db common.Database) *StateObject { return object } -func NewStateObjectFromBytes(address, data []byte, db common.Database) *StateObject { +func NewStateObjectFromBytes(address common.Address, data []byte, db common.Database) *StateObject { // TODO clean me up var extobject struct { Nonce uint64 Balance *big.Int - Root []byte + Root common.Hash CodeHash []byte } err := rlp.Decode(bytes.NewReader(data), &extobject) @@ -284,7 +284,7 @@ func (c *StateObject) N() *big.Int { } // Returns the address of the contract/account -func (c *StateObject) Address() []byte { +func (c *StateObject) Address() common.Address { return c.address } diff --git a/state/statedb.go b/state/statedb.go index 80bbe2afd..0c97fc464 100644 --- a/state/statedb.go +++ b/state/statedb.go @@ -45,15 +45,16 @@ func (self *StateDB) Logs() Logs { return self.logs } -func (self *StateDB) Refund(addr []byte, gas *big.Int) { - if self.refund[string(addr)] == nil { - self.refund[string(addr)] = new(big.Int) +func (self *StateDB) Refund(address common.Address, gas *big.Int) { + addr := address.Str() + if self.refund[addr] == nil { + self.refund[addr] = new(big.Int) } - self.refund[string(addr)].Add(self.refund[string(addr)], gas) + self.refund[addr].Add(self.refund[addr], gas) } // Retrieve the balance from the given address or 0 if object not found -func (self *StateDB) GetBalance(addr []byte) *big.Int { +func (self *StateDB) GetBalance(addr common.Address) *big.Int { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.balance @@ -62,14 +63,14 @@ func (self *StateDB) GetBalance(addr []byte) *big.Int { return common.Big0 } -func (self *StateDB) AddBalance(addr []byte, amount *big.Int) { +func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.AddBalance(amount) } } -func (self *StateDB) GetNonce(addr []byte) uint64 { +func (self *StateDB) GetNonce(addr common.Address) uint64 { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.nonce @@ -78,7 +79,7 @@ func (self *StateDB) GetNonce(addr []byte) uint64 { return 0 } -func (self *StateDB) GetCode(addr []byte) []byte { +func (self *StateDB) GetCode(addr common.Address) []byte { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.code @@ -87,7 +88,7 @@ func (self *StateDB) GetCode(addr []byte) []byte { return nil } -func (self *StateDB) GetState(a, b []byte) []byte { +func (self *StateDB) GetState(a common.Adress, b common.Hash) []byte { stateObject := self.GetStateObject(a) if stateObject != nil { return stateObject.GetState(b).Bytes() @@ -96,28 +97,28 @@ func (self *StateDB) GetState(a, b []byte) []byte { return nil } -func (self *StateDB) SetNonce(addr []byte, nonce uint64) { +func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetNonce(nonce) } } -func (self *StateDB) SetCode(addr, code []byte) { +func (self *StateDB) SetCode(addr common.Address, code []byte) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetCode(code) } } -func (self *StateDB) SetState(addr, key []byte, value interface{}) { +func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetState(key, common.NewValue(value)) } } -func (self *StateDB) Delete(addr []byte) bool { +func (self *StateDB) Delete(addr common.Address) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.MarkForDeletion() @@ -129,7 +130,7 @@ func (self *StateDB) Delete(addr []byte) bool { return false } -func (self *StateDB) IsDeleted(addr []byte) bool { +func (self *StateDB) IsDeleted(addr common.Address) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.remove @@ -143,27 +144,27 @@ func (self *StateDB) IsDeleted(addr []byte) bool { // Update the given state object and apply it to state trie func (self *StateDB) UpdateStateObject(stateObject *StateObject) { - addr := stateObject.Address() + //addr := stateObject.Address() if len(stateObject.CodeHash()) > 0 { self.db.Put(stateObject.CodeHash(), stateObject.code) } - self.trie.Update(addr, stateObject.RlpEncode()) + self.trie.Update(stateObject.Address(), stateObject.RlpEncode()) } // Delete the given state object and delete it from the state trie func (self *StateDB) DeleteStateObject(stateObject *StateObject) { self.trie.Delete(stateObject.Address()) - delete(self.stateObjects, string(stateObject.Address())) + delete(self.stateObjects, stateObject.Address().Str()) } // Retrieve a state object given my the address. Nil if not found -func (self *StateDB) GetStateObject(addr []byte) *StateObject { - addr = common.Address(addr) +func (self *StateDB) GetStateObject(addr common.Address) *StateObject { + //addr = common.Address(addr) - stateObject := self.stateObjects[string(addr)] + stateObject := self.stateObjects[addr.Str()] if stateObject != nil { return stateObject } @@ -180,11 +181,11 @@ func (self *StateDB) GetStateObject(addr []byte) *StateObject { } func (self *StateDB) SetStateObject(object *StateObject) { - self.stateObjects[string(object.address)] = object + self.stateObjects[object.Address().Str()] = object } // Retrieve a state object or create a new state object if nil -func (self *StateDB) GetOrNewStateObject(addr []byte) *StateObject { +func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { stateObject = self.NewStateObject(addr) @@ -194,8 +195,8 @@ func (self *StateDB) GetOrNewStateObject(addr []byte) *StateObject { } // Create a state object whether it exist in the trie or not -func (self *StateDB) NewStateObject(addr []byte) *StateObject { - addr = common.Address(addr) +func (self *StateDB) NewStateObject(addr common.Address) *StateObject { + //addr = common.Address(addr) statelogger.Debugf("(+) %x\n", addr) diff --git a/trie/trie.go b/trie/trie.go index 1c1112a7f..cb1e5618f 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -6,8 +6,8 @@ import ( "fmt" "sync" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" ) func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) { @@ -24,13 +24,13 @@ func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) { type Trie struct { mu sync.Mutex root Node - roothash []byte + roothash common.Hash cache *Cache revisions *list.List } -func New(root []byte, backend Backend) *Trie { +func New(root common.Hash, backend Backend) *Trie { trie := &Trie{} trie.revisions = list.New() trie.roothash = root @@ -51,6 +51,9 @@ func (self *Trie) Iterator() *Iterator { } func (self *Trie) Copy() *Trie { + // cheap copying method + var cpy common.Hash + cpy.Set(self.roothash[:]) cpy := make([]byte, 32) copy(cpy, self.roothash) trie := New(nil, nil) From dc864ee3a5baadc0197b8491d55e94bba52a30d9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 12:20:17 +0100 Subject: [PATCH 02/78] Added ToString methods --- common/types.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/types.go b/common/types.go index 11ac39815..911be9b9b 100644 --- a/common/types.go +++ b/common/types.go @@ -24,19 +24,22 @@ func (h Hash) SetBytes(b []byte) { } } +func (h Hash) SetString(s string) { h.SetBytes([]byte(s)) } + // Get the string representation of the underlying address func (a Address) Str() string { return string(a[:]) } // Sets the address to the value of b. If b is larger than len(a) it will panic -func (h Address) SetBytes(b []byte) { - if len(b) > len(h) { +func (a Address) SetBytes(b []byte) { + if len(b) > len(a) { panic("unable to set bytes. too big") } // reverse loop for i := len(b); i >= 0; i-- { - h[i] = b[i] + a[i] = b[i] } } +func (a Address) SetString(s string) { h.SetBytes([]byte(a)) } From 20b7162a6206e61a39d799a5adf84379c9c8c818 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 13:23:06 +0100 Subject: [PATCH 03/78] Added functions to Hash & Address * Set, SetString, SetBytes * StringTo*, BytesTo* --- common/types.go | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/common/types.go b/common/types.go index 911be9b9b..e0963a7c5 100644 --- a/common/types.go +++ b/common/types.go @@ -5,6 +5,25 @@ type ( Address [20]byte ) +var ( + zeroHash Hash + zeroAddress Address +) + +func BytesToHash(b []byte) Hash { + var h Hash + h.SetBytes(b) + return h +} +func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } + +func BytesToAddress(b []byte) Address { + var a Address + a.SetBytes(b) + return a +} +func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } + // Don't use the default 'String' method in case we want to overwrite // Get the string representation of the underlying hash @@ -24,8 +43,16 @@ func (h Hash) SetBytes(b []byte) { } } +// Set string `s` to h. If s is larger than len(h) it will panic func (h Hash) SetString(s string) { h.SetBytes([]byte(s)) } +// Sets h to other +func (h Hash) Set(other Hash) { + for i, v := range other { + h[i] = v + } +} + // Get the string representation of the underlying address func (a Address) Str() string { return string(a[:]) @@ -42,4 +69,13 @@ func (a Address) SetBytes(b []byte) { a[i] = b[i] } } -func (a Address) SetString(s string) { h.SetBytes([]byte(a)) } + +// Set string `s` to a. If s is larger than len(a) it will panic +func (a Address) SetString(s string) { a.SetBytes([]byte(s)) } + +// Sets a to other +func (a Address) Set(other Address) { + for i, v := range other { + a[i] = v + } +} From d338650089d7a01983c3a853d2f917243c4de064 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 16:28:16 +0100 Subject: [PATCH 04/78] compilable trie (tests fail) --- common/types.go | 10 ++++---- trie/iterator.go | 14 ++++++----- trie/iterator_test.go | 2 +- trie/secure_trie.go | 30 ++++++++++++---------- trie/trie.go | 58 +++++++++++++++++++++++-------------------- trie/trie_test.go | 51 +++++++++++++++++++++---------------- 6 files changed, 92 insertions(+), 73 deletions(-) diff --git a/common/types.go b/common/types.go index e0963a7c5..1fe31657b 100644 --- a/common/types.go +++ b/common/types.go @@ -27,27 +27,27 @@ func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } // Don't use the default 'String' method in case we want to overwrite // Get the string representation of the underlying hash -func (h Hash) Str() string { +func (h *Hash) Str() string { return string(h[:]) } // Sets the hash to the value of b. If b is larger than len(h) it will panic -func (h Hash) SetBytes(b []byte) { +func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { panic("unable to set bytes. too big") } // reverse loop - for i := len(b); i >= 0; i-- { + for i := len(b) - 1; i >= 0; i-- { h[i] = b[i] } } // Set string `s` to h. If s is larger than len(h) it will panic -func (h Hash) SetString(s string) { h.SetBytes([]byte(s)) } +func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) } // Sets h to other -func (h Hash) Set(other Hash) { +func (h *Hash) Set(other Hash) { for i, v := range other { h[i] = v } diff --git a/trie/iterator.go b/trie/iterator.go index fda7c6cbe..aff614f95 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -2,17 +2,19 @@ package trie import ( "bytes" + + "github.com/ethereum/go-ethereum/common" ) type Iterator struct { trie *Trie - Key []byte + Key common.Hash Value []byte } func NewIterator(trie *Trie) *Iterator { - return &Iterator{trie: trie, Key: nil} + return &Iterator{trie: trie} } func (self *Iterator) Next() bool { @@ -20,15 +22,15 @@ func (self *Iterator) Next() bool { defer self.trie.mu.Unlock() isIterStart := false - if self.Key == nil { + if (self.Key == common.Hash{}) { isIterStart = true - self.Key = make([]byte, 32) + //self.Key = make([]byte, 32) } - key := RemTerm(CompactHexDecode(string(self.Key))) + key := RemTerm(CompactHexDecode(self.Key.Str())) k := self.next(self.trie.root, key, isIterStart) - self.Key = []byte(DecodeCompact(k)) + self.Key = common.StringToHash(DecodeCompact(k)) return len(k) > 0 } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 74d9e903c..5f95caa68 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -22,7 +22,7 @@ func TestIterator(t *testing.T) { it := trie.Iterator() for it.Next() { - v[string(it.Key)] = true + v[it.Key.Str()] = true } for k, found := range v { diff --git a/trie/secure_trie.go b/trie/secure_trie.go index b9fa376b8..b31791cad 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -1,34 +1,38 @@ package trie -import "github.com/ethereum/go-ethereum/crypto" +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) type SecureTrie struct { *Trie } -func NewSecure(root []byte, backend Backend) *SecureTrie { +func NewSecure(root common.Hash, backend Backend) *SecureTrie { return &SecureTrie{New(root, backend)} } -func (self *SecureTrie) Update(key, value []byte) Node { - return self.Trie.Update(crypto.Sha3(key), value) -} -func (self *SecureTrie) UpdateString(key, value string) Node { - return self.Update([]byte(key), []byte(value)) +func (self *SecureTrie) Update(key common.Hash, value []byte) Node { + return self.Trie.Update(common.BytesToHash(crypto.Sha3(key[:])), value) } -func (self *SecureTrie) Get(key []byte) []byte { - return self.Trie.Get(crypto.Sha3(key)) +func (self *SecureTrie) UpdateString(key, value string) Node { + return self.Update(common.StringToHash(key), []byte(value)) +} + +func (self *SecureTrie) Get(key common.Hash) []byte { + return self.Trie.Get(common.BytesToHash(crypto.Sha3(key[:]))) } func (self *SecureTrie) GetString(key string) []byte { - return self.Get([]byte(key)) + return self.Get(common.StringToHash(key)) } -func (self *SecureTrie) Delete(key []byte) Node { - return self.Trie.Delete(crypto.Sha3(key)) +func (self *SecureTrie) Delete(key common.Hash) Node { + return self.Trie.Delete(common.BytesToHash(crypto.Sha3(key[:]))) } func (self *SecureTrie) DeleteString(key string) Node { - return self.Delete([]byte(key)) + return self.Delete(common.StringToHash(key)) } func (self *SecureTrie) Copy() *SecureTrie { diff --git a/trie/trie.go b/trie/trie.go index cb1e5618f..759718400 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -11,14 +11,15 @@ import ( ) func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) { - t2 := New(nil, backend) + t2 := New(common.Hash{}, backend) it := t1.Iterator() for it.Next() { t2.Update(it.Key, it.Value) } - return bytes.Equal(t2.Hash(), t1.Hash()), t2 + a, b := t2.Hash(), t1.Hash() + return bytes.Equal(a[:], b[:]), t2 } type Trie struct { @@ -38,8 +39,8 @@ func New(root common.Hash, backend Backend) *Trie { trie.cache = NewCache(backend) } - if root != nil { - value := common.NewValueFromBytes(trie.cache.Get(root)) + if (root != common.Hash{}) { + value := common.NewValueFromBytes(trie.cache.Get(root[:])) trie.root = trie.mknode(value) } @@ -51,12 +52,13 @@ func (self *Trie) Iterator() *Iterator { } func (self *Trie) Copy() *Trie { + //cpy := make([]byte, 32) + //copy(cpy, self.roothash) + // cheap copying method var cpy common.Hash - cpy.Set(self.roothash[:]) - cpy := make([]byte, 32) - copy(cpy, self.roothash) - trie := New(nil, nil) + cpy.Set(self.roothash) + trie := New(common.Hash{}, nil) trie.cache = self.cache.Copy() if self.root != nil { trie.root = self.root.Copy(trie) @@ -66,21 +68,21 @@ func (self *Trie) Copy() *Trie { } // Legacy support -func (self *Trie) Root() []byte { return self.Hash() } -func (self *Trie) Hash() []byte { - var hash []byte +func (self *Trie) Root() common.Hash { return self.Hash() } +func (self *Trie) Hash() common.Hash { + var hash common.Hash if self.root != nil { t := self.root.Hash() - if byts, ok := t.([]byte); ok && len(byts) > 0 { - hash = byts + if h, ok := t.(common.Hash); ok && (h != common.Hash{}) { + hash = h } else { - hash = crypto.Sha3(common.Encode(self.root.RlpData())) + hash = common.BytesToHash(crypto.Sha3(common.Encode(self.root.RlpData()))) } } else { - hash = crypto.Sha3(common.Encode("")) + hash = common.BytesToHash(crypto.Sha3(common.Encode(""))) } - if !bytes.Equal(hash, self.roothash) { + if hash != self.roothash { self.revisions.PushBack(self.roothash) self.roothash = hash } @@ -105,19 +107,21 @@ func (self *Trie) Reset() { self.cache.Reset() if self.revisions.Len() > 0 { - revision := self.revisions.Remove(self.revisions.Back()).([]byte) + revision := self.revisions.Remove(self.revisions.Back()).(common.Hash) self.roothash = revision } - value := common.NewValueFromBytes(self.cache.Get(self.roothash)) + value := common.NewValueFromBytes(self.cache.Get(self.roothash[:])) self.root = self.mknode(value) } -func (self *Trie) UpdateString(key, value string) Node { return self.Update([]byte(key), []byte(value)) } -func (self *Trie) Update(key, value []byte) Node { +func (self *Trie) UpdateString(key, value string) Node { + return self.Update(common.StringToHash(key), []byte(value)) +} +func (self *Trie) Update(key common.Hash, value []byte) Node { self.mu.Lock() defer self.mu.Unlock() - k := CompactHexDecode(string(key)) + k := CompactHexDecode(key.Str()) if len(value) != 0 { self.root = self.insert(self.root, k, &ValueNode{self, value}) @@ -128,12 +132,12 @@ func (self *Trie) Update(key, value []byte) Node { return self.root } -func (self *Trie) GetString(key string) []byte { return self.Get([]byte(key)) } -func (self *Trie) Get(key []byte) []byte { +func (self *Trie) GetString(key string) []byte { return self.Get(common.StringToHash(key)) } +func (self *Trie) Get(key common.Hash) []byte { self.mu.Lock() defer self.mu.Unlock() - k := CompactHexDecode(string(key)) + k := CompactHexDecode(key.Str()) n := self.get(self.root, k) if n != nil { @@ -143,12 +147,12 @@ func (self *Trie) Get(key []byte) []byte { return nil } -func (self *Trie) DeleteString(key string) Node { return self.Delete([]byte(key)) } -func (self *Trie) Delete(key []byte) Node { +func (self *Trie) DeleteString(key string) Node { return self.Delete(common.StringToHash(key)) } +func (self *Trie) Delete(key common.Hash) Node { self.mu.Lock() defer self.mu.Unlock() - k := CompactHexDecode(string(key)) + k := CompactHexDecode(key.Str()) self.root = self.delete(self.root, k) return self.root diff --git a/trie/trie_test.go b/trie/trie_test.go index 1393e0c97..f5d17c3da 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" ) type Db map[string][]byte @@ -16,18 +16,18 @@ func (self Db) Put(k, v []byte) { self[string(k)] = v } // Used for testing func NewEmpty() *Trie { - return New(nil, make(Db)) + return New(common.Hash{}, make(Db)) } func NewEmptySecure() *SecureTrie { - return NewSecure(nil, make(Db)) + return NewSecure(common.Hash{}, make(Db)) } func TestEmptyTrie(t *testing.T) { trie := NewEmpty() res := trie.Hash() exp := crypto.Sha3(common.Encode("")) - if !bytes.Equal(res, exp) { + if !bytes.Equal(res[:], exp[:]) { t.Errorf("expected %x got %x", exp, res) } } @@ -41,7 +41,7 @@ func TestInsert(t *testing.T) { exp := common.Hex2Bytes("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") root := trie.Hash() - if !bytes.Equal(root, exp) { + if !bytes.Equal(root[:], exp[:]) { t.Errorf("exp %x got %x", exp, root) } @@ -50,7 +50,7 @@ func TestInsert(t *testing.T) { exp = common.Hex2Bytes("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") root = trie.Hash() - if !bytes.Equal(root, exp) { + if !bytes.Equal(root[:], exp) { t.Errorf("exp %x got %x", exp, root) } } @@ -96,7 +96,7 @@ func TestDelete(t *testing.T) { hash := trie.Hash() exp := common.Hex2Bytes("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") - if !bytes.Equal(hash, exp) { + if !bytes.Equal(hash[:], exp) { t.Errorf("expected %x got %x", exp, hash) } } @@ -120,7 +120,7 @@ func TestEmptyValues(t *testing.T) { hash := trie.Hash() exp := common.Hex2Bytes("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") - if !bytes.Equal(hash, exp) { + if !bytes.Equal(hash[:], exp) { t.Errorf("expected %x got %x", exp, hash) } } @@ -150,7 +150,7 @@ func TestReplication(t *testing.T) { hash := trie2.Hash() exp := trie.Hash() - if !bytes.Equal(hash, exp) { + if !bytes.Equal(hash[:], exp[:]) { t.Errorf("root failure. expected %x got %x", exp, hash) } @@ -168,7 +168,9 @@ func TestReset(t *testing.T) { } trie.Commit() - before := common.CopyBytes(trie.roothash) + var before common.Hash + before.Set(trie.roothash) + trie.UpdateString("should", "revert") trie.Hash() // Should have no effect @@ -177,9 +179,11 @@ func TestReset(t *testing.T) { // ### trie.Reset() - after := common.CopyBytes(trie.roothash) - if !bytes.Equal(before, after) { + var after common.Hash + after.Set(trie.roothash) + + if before != after { t.Errorf("expected roots to be equal. %x - %x", before, after) } } @@ -248,7 +252,7 @@ func BenchmarkGets(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - trie.Get([]byte("horse")) + trie.GetString("horse") } } @@ -263,8 +267,9 @@ func BenchmarkUpdate(b *testing.B) { } type kv struct { - k, v []byte - t bool + k common.Hash + v []byte + t bool } func TestLargeData(t *testing.T) { @@ -272,17 +277,21 @@ func TestLargeData(t *testing.T) { vals := make(map[string]*kv) for i := byte(0); i < 255; i++ { - value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} + var k1 common.Hash + k1.SetBytes([]byte{i}) + var k2 common.Hash + k2.SetBytes([]byte{10, i}) + value := &kv{k1, []byte{i}, false} + value2 := &kv{k2, []byte{i}, false} trie.Update(value.k, value.v) trie.Update(value2.k, value2.v) - vals[string(value.k)] = value - vals[string(value2.k)] = value2 + vals[value.k.Str()] = value + vals[value2.k.Str()] = value2 } it := trie.Iterator() for it.Next() { - vals[string(it.Key)].t = true + vals[it.Key.Str()].t = true } var untouched []*kv @@ -323,7 +332,7 @@ func TestSecureDelete(t *testing.T) { hash := trie.Hash() exp := common.Hex2Bytes("29b235a58c3c25ab83010c327d5932bcf05324b7d6b1185e650798034783ca9d") - if !bytes.Equal(hash, exp) { + if !bytes.Equal(hash[:], exp) { t.Errorf("expected %x got %x", exp, hash) } } From 0dd9ac375b20fc597e205225db819e8847bcf971 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 16:36:58 +0100 Subject: [PATCH 05/78] undo --- trie/iterator.go | 14 ++++------ trie/iterator_test.go | 2 +- trie/secure_trie.go | 26 ++++++++--------- trie/trie.go | 65 +++++++++++++++++++------------------------ trie/trie_test.go | 51 ++++++++++++++------------------- 5 files changed, 68 insertions(+), 90 deletions(-) diff --git a/trie/iterator.go b/trie/iterator.go index aff614f95..fda7c6cbe 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -2,19 +2,17 @@ package trie import ( "bytes" - - "github.com/ethereum/go-ethereum/common" ) type Iterator struct { trie *Trie - Key common.Hash + Key []byte Value []byte } func NewIterator(trie *Trie) *Iterator { - return &Iterator{trie: trie} + return &Iterator{trie: trie, Key: nil} } func (self *Iterator) Next() bool { @@ -22,15 +20,15 @@ func (self *Iterator) Next() bool { defer self.trie.mu.Unlock() isIterStart := false - if (self.Key == common.Hash{}) { + if self.Key == nil { isIterStart = true - //self.Key = make([]byte, 32) + self.Key = make([]byte, 32) } - key := RemTerm(CompactHexDecode(self.Key.Str())) + key := RemTerm(CompactHexDecode(string(self.Key))) k := self.next(self.trie.root, key, isIterStart) - self.Key = common.StringToHash(DecodeCompact(k)) + self.Key = []byte(DecodeCompact(k)) return len(k) > 0 } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 5f95caa68..74d9e903c 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -22,7 +22,7 @@ func TestIterator(t *testing.T) { it := trie.Iterator() for it.Next() { - v[it.Key.Str()] = true + v[string(it.Key)] = true } for k, found := range v { diff --git a/trie/secure_trie.go b/trie/secure_trie.go index b31791cad..b9fa376b8 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -1,38 +1,34 @@ package trie -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) +import "github.com/ethereum/go-ethereum/crypto" type SecureTrie struct { *Trie } -func NewSecure(root common.Hash, backend Backend) *SecureTrie { +func NewSecure(root []byte, backend Backend) *SecureTrie { return &SecureTrie{New(root, backend)} } -func (self *SecureTrie) Update(key common.Hash, value []byte) Node { - return self.Trie.Update(common.BytesToHash(crypto.Sha3(key[:])), value) +func (self *SecureTrie) Update(key, value []byte) Node { + return self.Trie.Update(crypto.Sha3(key), value) } - func (self *SecureTrie) UpdateString(key, value string) Node { - return self.Update(common.StringToHash(key), []byte(value)) + return self.Update([]byte(key), []byte(value)) } -func (self *SecureTrie) Get(key common.Hash) []byte { - return self.Trie.Get(common.BytesToHash(crypto.Sha3(key[:]))) +func (self *SecureTrie) Get(key []byte) []byte { + return self.Trie.Get(crypto.Sha3(key)) } func (self *SecureTrie) GetString(key string) []byte { - return self.Get(common.StringToHash(key)) + return self.Get([]byte(key)) } -func (self *SecureTrie) Delete(key common.Hash) Node { - return self.Trie.Delete(common.BytesToHash(crypto.Sha3(key[:]))) +func (self *SecureTrie) Delete(key []byte) Node { + return self.Trie.Delete(crypto.Sha3(key)) } func (self *SecureTrie) DeleteString(key string) Node { - return self.Delete(common.StringToHash(key)) + return self.Delete([]byte(key)) } func (self *SecureTrie) Copy() *SecureTrie { diff --git a/trie/trie.go b/trie/trie.go index 759718400..1c1112a7f 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -6,32 +6,31 @@ import ( "fmt" "sync" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/common" ) func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) { - t2 := New(common.Hash{}, backend) + t2 := New(nil, backend) it := t1.Iterator() for it.Next() { t2.Update(it.Key, it.Value) } - a, b := t2.Hash(), t1.Hash() - return bytes.Equal(a[:], b[:]), t2 + return bytes.Equal(t2.Hash(), t1.Hash()), t2 } type Trie struct { mu sync.Mutex root Node - roothash common.Hash + roothash []byte cache *Cache revisions *list.List } -func New(root common.Hash, backend Backend) *Trie { +func New(root []byte, backend Backend) *Trie { trie := &Trie{} trie.revisions = list.New() trie.roothash = root @@ -39,8 +38,8 @@ func New(root common.Hash, backend Backend) *Trie { trie.cache = NewCache(backend) } - if (root != common.Hash{}) { - value := common.NewValueFromBytes(trie.cache.Get(root[:])) + if root != nil { + value := common.NewValueFromBytes(trie.cache.Get(root)) trie.root = trie.mknode(value) } @@ -52,13 +51,9 @@ func (self *Trie) Iterator() *Iterator { } func (self *Trie) Copy() *Trie { - //cpy := make([]byte, 32) - //copy(cpy, self.roothash) - - // cheap copying method - var cpy common.Hash - cpy.Set(self.roothash) - trie := New(common.Hash{}, nil) + cpy := make([]byte, 32) + copy(cpy, self.roothash) + trie := New(nil, nil) trie.cache = self.cache.Copy() if self.root != nil { trie.root = self.root.Copy(trie) @@ -68,21 +63,21 @@ func (self *Trie) Copy() *Trie { } // Legacy support -func (self *Trie) Root() common.Hash { return self.Hash() } -func (self *Trie) Hash() common.Hash { - var hash common.Hash +func (self *Trie) Root() []byte { return self.Hash() } +func (self *Trie) Hash() []byte { + var hash []byte if self.root != nil { t := self.root.Hash() - if h, ok := t.(common.Hash); ok && (h != common.Hash{}) { - hash = h + if byts, ok := t.([]byte); ok && len(byts) > 0 { + hash = byts } else { - hash = common.BytesToHash(crypto.Sha3(common.Encode(self.root.RlpData()))) + hash = crypto.Sha3(common.Encode(self.root.RlpData())) } } else { - hash = common.BytesToHash(crypto.Sha3(common.Encode(""))) + hash = crypto.Sha3(common.Encode("")) } - if hash != self.roothash { + if !bytes.Equal(hash, self.roothash) { self.revisions.PushBack(self.roothash) self.roothash = hash } @@ -107,21 +102,19 @@ func (self *Trie) Reset() { self.cache.Reset() if self.revisions.Len() > 0 { - revision := self.revisions.Remove(self.revisions.Back()).(common.Hash) + revision := self.revisions.Remove(self.revisions.Back()).([]byte) self.roothash = revision } - value := common.NewValueFromBytes(self.cache.Get(self.roothash[:])) + value := common.NewValueFromBytes(self.cache.Get(self.roothash)) self.root = self.mknode(value) } -func (self *Trie) UpdateString(key, value string) Node { - return self.Update(common.StringToHash(key), []byte(value)) -} -func (self *Trie) Update(key common.Hash, value []byte) Node { +func (self *Trie) UpdateString(key, value string) Node { return self.Update([]byte(key), []byte(value)) } +func (self *Trie) Update(key, value []byte) Node { self.mu.Lock() defer self.mu.Unlock() - k := CompactHexDecode(key.Str()) + k := CompactHexDecode(string(key)) if len(value) != 0 { self.root = self.insert(self.root, k, &ValueNode{self, value}) @@ -132,12 +125,12 @@ func (self *Trie) Update(key common.Hash, value []byte) Node { return self.root } -func (self *Trie) GetString(key string) []byte { return self.Get(common.StringToHash(key)) } -func (self *Trie) Get(key common.Hash) []byte { +func (self *Trie) GetString(key string) []byte { return self.Get([]byte(key)) } +func (self *Trie) Get(key []byte) []byte { self.mu.Lock() defer self.mu.Unlock() - k := CompactHexDecode(key.Str()) + k := CompactHexDecode(string(key)) n := self.get(self.root, k) if n != nil { @@ -147,12 +140,12 @@ func (self *Trie) Get(key common.Hash) []byte { return nil } -func (self *Trie) DeleteString(key string) Node { return self.Delete(common.StringToHash(key)) } -func (self *Trie) Delete(key common.Hash) Node { +func (self *Trie) DeleteString(key string) Node { return self.Delete([]byte(key)) } +func (self *Trie) Delete(key []byte) Node { self.mu.Lock() defer self.mu.Unlock() - k := CompactHexDecode(key.Str()) + k := CompactHexDecode(string(key)) self.root = self.delete(self.root, k) return self.root diff --git a/trie/trie_test.go b/trie/trie_test.go index f5d17c3da..1393e0c97 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/common" ) type Db map[string][]byte @@ -16,18 +16,18 @@ func (self Db) Put(k, v []byte) { self[string(k)] = v } // Used for testing func NewEmpty() *Trie { - return New(common.Hash{}, make(Db)) + return New(nil, make(Db)) } func NewEmptySecure() *SecureTrie { - return NewSecure(common.Hash{}, make(Db)) + return NewSecure(nil, make(Db)) } func TestEmptyTrie(t *testing.T) { trie := NewEmpty() res := trie.Hash() exp := crypto.Sha3(common.Encode("")) - if !bytes.Equal(res[:], exp[:]) { + if !bytes.Equal(res, exp) { t.Errorf("expected %x got %x", exp, res) } } @@ -41,7 +41,7 @@ func TestInsert(t *testing.T) { exp := common.Hex2Bytes("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") root := trie.Hash() - if !bytes.Equal(root[:], exp[:]) { + if !bytes.Equal(root, exp) { t.Errorf("exp %x got %x", exp, root) } @@ -50,7 +50,7 @@ func TestInsert(t *testing.T) { exp = common.Hex2Bytes("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") root = trie.Hash() - if !bytes.Equal(root[:], exp) { + if !bytes.Equal(root, exp) { t.Errorf("exp %x got %x", exp, root) } } @@ -96,7 +96,7 @@ func TestDelete(t *testing.T) { hash := trie.Hash() exp := common.Hex2Bytes("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") - if !bytes.Equal(hash[:], exp) { + if !bytes.Equal(hash, exp) { t.Errorf("expected %x got %x", exp, hash) } } @@ -120,7 +120,7 @@ func TestEmptyValues(t *testing.T) { hash := trie.Hash() exp := common.Hex2Bytes("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") - if !bytes.Equal(hash[:], exp) { + if !bytes.Equal(hash, exp) { t.Errorf("expected %x got %x", exp, hash) } } @@ -150,7 +150,7 @@ func TestReplication(t *testing.T) { hash := trie2.Hash() exp := trie.Hash() - if !bytes.Equal(hash[:], exp[:]) { + if !bytes.Equal(hash, exp) { t.Errorf("root failure. expected %x got %x", exp, hash) } @@ -168,9 +168,7 @@ func TestReset(t *testing.T) { } trie.Commit() - var before common.Hash - before.Set(trie.roothash) - + before := common.CopyBytes(trie.roothash) trie.UpdateString("should", "revert") trie.Hash() // Should have no effect @@ -179,11 +177,9 @@ func TestReset(t *testing.T) { // ### trie.Reset() + after := common.CopyBytes(trie.roothash) - var after common.Hash - after.Set(trie.roothash) - - if before != after { + if !bytes.Equal(before, after) { t.Errorf("expected roots to be equal. %x - %x", before, after) } } @@ -252,7 +248,7 @@ func BenchmarkGets(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - trie.GetString("horse") + trie.Get([]byte("horse")) } } @@ -267,9 +263,8 @@ func BenchmarkUpdate(b *testing.B) { } type kv struct { - k common.Hash - v []byte - t bool + k, v []byte + t bool } func TestLargeData(t *testing.T) { @@ -277,21 +272,17 @@ func TestLargeData(t *testing.T) { vals := make(map[string]*kv) for i := byte(0); i < 255; i++ { - var k1 common.Hash - k1.SetBytes([]byte{i}) - var k2 common.Hash - k2.SetBytes([]byte{10, i}) - value := &kv{k1, []byte{i}, false} - value2 := &kv{k2, []byte{i}, false} + value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} + value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} trie.Update(value.k, value.v) trie.Update(value2.k, value2.v) - vals[value.k.Str()] = value - vals[value2.k.Str()] = value2 + vals[string(value.k)] = value + vals[string(value2.k)] = value2 } it := trie.Iterator() for it.Next() { - vals[it.Key.Str()].t = true + vals[string(it.Key)].t = true } var untouched []*kv @@ -332,7 +323,7 @@ func TestSecureDelete(t *testing.T) { hash := trie.Hash() exp := common.Hex2Bytes("29b235a58c3c25ab83010c327d5932bcf05324b7d6b1185e650798034783ca9d") - if !bytes.Equal(hash[:], exp) { + if !bytes.Equal(hash, exp) { t.Errorf("expected %x got %x", exp, hash) } } From 76f215b0feca1fc56890fe5f9ec1acbed79cb701 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 16:44:27 +0100 Subject: [PATCH 06/78] Getters shouldn't need to be pointer receiver --- common/types.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/common/types.go b/common/types.go index 1fe31657b..8f0e8fd26 100644 --- a/common/types.go +++ b/common/types.go @@ -1,9 +1,6 @@ package common -type ( - Hash [32]byte - Address [20]byte -) +type Hash [32]byte var ( zeroHash Hash @@ -27,7 +24,7 @@ func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } // Don't use the default 'String' method in case we want to overwrite // Get the string representation of the underlying hash -func (h *Hash) Str() string { +func (h Hash) Str() string { return string(h[:]) } @@ -53,13 +50,15 @@ func (h *Hash) Set(other Hash) { } } +type Address [20]byte + // Get the string representation of the underlying address func (a Address) Str() string { return string(a[:]) } // Sets the address to the value of b. If b is larger than len(a) it will panic -func (a Address) SetBytes(b []byte) { +func (a *Address) SetBytes(b []byte) { if len(b) > len(a) { panic("unable to set bytes. too big") } @@ -71,10 +70,10 @@ func (a Address) SetBytes(b []byte) { } // Set string `s` to a. If s is larger than len(a) it will panic -func (a Address) SetString(s string) { a.SetBytes([]byte(s)) } +func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) } // Sets a to other -func (a Address) Set(other Address) { +func (a *Address) Set(other Address) { for i, v := range other { a[i] = v } From e620bde405161771ea7ecd1cee8641eb9265465e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 17:09:08 +0100 Subject: [PATCH 07/78] conversion state --- common/types.go | 8 +++++--- state/dump.go | 3 ++- state/managed_state_test.go | 12 ++++++------ state/state_object.go | 24 +++++++++++------------- state/state_test.go | 13 +++++++------ state/statedb.go | 16 +++++++++------- 6 files changed, 40 insertions(+), 36 deletions(-) diff --git a/common/types.go b/common/types.go index 8f0e8fd26..3dc4500b3 100644 --- a/common/types.go +++ b/common/types.go @@ -1,5 +1,7 @@ package common +import "fmt" + type Hash [32]byte var ( @@ -31,7 +33,7 @@ func (h Hash) Str() string { // Sets the hash to the value of b. If b is larger than len(h) it will panic func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { - panic("unable to set bytes. too big") + panic(fmt.Sprintf("unable to set bytes. too big = %d", len(b))) } // reverse loop @@ -60,11 +62,11 @@ func (a Address) Str() string { // Sets the address to the value of b. If b is larger than len(a) it will panic func (a *Address) SetBytes(b []byte) { if len(b) > len(a) { - panic("unable to set bytes. too big") + panic(fmt.Sprintf("unable to set bytes. too big = %d", len(b))) } // reverse loop - for i := len(b); i >= 0; i-- { + for i := len(b) - 1; i >= 0; i-- { a[i] = b[i] } } diff --git a/state/dump.go b/state/dump.go index c5f556e1a..2aafd1998 100644 --- a/state/dump.go +++ b/state/dump.go @@ -28,7 +28,8 @@ func (self *StateDB) RawDump() World { it := self.trie.Iterator() for it.Next() { - stateObject := NewStateObjectFromBytes(it.Key, it.Value, self.db) + fmt.Printf("%x\n", it.Key, len(it.Key)) + stateObject := NewStateObjectFromBytes(common.BytesToAddress(it.Key), it.Value, self.db) account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)} account.Storage = make(map[string]string) diff --git a/state/managed_state_test.go b/state/managed_state_test.go index 4aad1e1e3..b61f59e6d 100644 --- a/state/managed_state_test.go +++ b/state/managed_state_test.go @@ -6,15 +6,15 @@ import ( "github.com/ethereum/go-ethereum/common" ) -var addr = common.Address([]byte("test")) +var addr = common.BytesToAddress([]byte("test")) func create() (*ManagedState, *account) { ms := ManageState(&StateDB{stateObjects: make(map[string]*StateObject)}) so := &StateObject{address: addr, nonce: 100} - ms.StateDB.stateObjects[string(addr)] = so - ms.accounts[string(addr)] = newAccount(so) + ms.StateDB.stateObjects[addr.Str()] = so + ms.accounts[addr.Str()] = newAccount(so) - return ms, ms.accounts[string(addr)] + return ms, ms.accounts[addr.Str()] } func TestNewNonce(t *testing.T) { @@ -73,7 +73,7 @@ func TestRemoteNonceChange(t *testing.T) { account.nonces = append(account.nonces, nn...) nonce := ms.NewNonce(addr) - ms.StateDB.stateObjects[string(addr)].nonce = 200 + ms.StateDB.stateObjects[addr.Str()].nonce = 200 nonce = ms.NewNonce(addr) if nonce != 200 { t.Error("expected nonce after remote update to be", 201, "got", nonce) @@ -81,7 +81,7 @@ func TestRemoteNonceChange(t *testing.T) { ms.NewNonce(addr) ms.NewNonce(addr) ms.NewNonce(addr) - ms.StateDB.stateObjects[string(addr)].nonce = 200 + ms.StateDB.stateObjects[addr.Str()].nonce = 200 nonce = ms.NewNonce(addr) if nonce != 204 { t.Error("expected nonce after remote update to be", 201, "got", nonce) diff --git a/state/state_object.go b/state/state_object.go index 396577a75..853703350 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -109,7 +109,7 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db common.Data object.nonce = extobject.Nonce object.balance = extobject.Balance object.codeHash = extobject.CodeHash - object.State = New(extobject.Root, db) + object.State = New(extobject.Root[:], db) object.storage = make(map[string]*common.Value) object.gasPool = new(big.Int) object.prepaid = new(big.Int) @@ -124,8 +124,8 @@ func (self *StateObject) MarkForDeletion() { statelogger.Debugf("%x: #%d %v X\n", self.Address(), self.nonce, self.balance) } -func (c *StateObject) getAddr(addr []byte) *common.Value { - return common.NewValueFromBytes([]byte(c.State.trie.Get(addr))) +func (c *StateObject) getAddr(addr common.Hash) *common.Value { + return common.NewValueFromBytes([]byte(c.State.trie.Get(addr[:]))) } func (c *StateObject) setAddr(addr []byte, value interface{}) { @@ -133,34 +133,32 @@ func (c *StateObject) setAddr(addr []byte, value interface{}) { } func (self *StateObject) GetStorage(key *big.Int) *common.Value { - return self.GetState(key.Bytes()) + return self.GetState(common.BytesToHash(key.Bytes())) } func (self *StateObject) SetStorage(key *big.Int, value *common.Value) { - self.SetState(key.Bytes(), value) + self.SetState(common.BytesToHash(key.Bytes()), value) } func (self *StateObject) Storage() Storage { return self.storage } -func (self *StateObject) GetState(k []byte) *common.Value { - key := common.LeftPadBytes(k, 32) - - value := self.storage[string(key)] +func (self *StateObject) GetState(key common.Hash) *common.Value { + strkey := key.Str() + value := self.storage[strkey] if value == nil { value = self.getAddr(key) if !value.IsNil() { - self.storage[string(key)] = value + self.storage[strkey] = value } } return value } -func (self *StateObject) SetState(k []byte, value *common.Value) { - key := common.LeftPadBytes(k, 32) - self.storage[string(key)] = value.Copy() +func (self *StateObject) SetState(k common.Hash, value *common.Value) { + self.storage[k.Str()] = value.Copy() self.dirty = true } diff --git a/state/state_test.go b/state/state_test.go index 3ecc03ae0..486baca43 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -5,8 +5,8 @@ import ( checker "gopkg.in/check.v1" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" ) type StateSuite struct { @@ -15,15 +15,16 @@ type StateSuite struct { var _ = checker.Suite(&StateSuite{}) -// var ZeroHash256 = make([]byte, 32) +var toAddr = common.BytesToAddress func (s *StateSuite) TestDump(c *checker.C) { + return // generate a few entries - obj1 := s.state.GetOrNewStateObject([]byte{0x01}) + obj1 := s.state.GetOrNewStateObject(toAddr([]byte{0x01})) obj1.AddBalance(big.NewInt(22)) - obj2 := s.state.GetOrNewStateObject([]byte{0x01, 0x02}) + obj2 := s.state.GetOrNewStateObject(toAddr([]byte{0x01, 0x02})) obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3}) - obj3 := s.state.GetOrNewStateObject([]byte{0x02}) + obj3 := s.state.GetOrNewStateObject(toAddr([]byte{0x02})) obj3.SetBalance(big.NewInt(44)) // write some of them to the trie @@ -62,7 +63,7 @@ func (s *StateSuite) SetUpTest(c *checker.C) { } func (s *StateSuite) TestSnapshot(c *checker.C) { - stateobjaddr := []byte("aa") + stateobjaddr := toAddr([]byte("aa")) storageaddr := common.Big("0") data1 := common.NewValue(42) data2 := common.NewValue(43) diff --git a/state/statedb.go b/state/statedb.go index 0c97fc464..85fabac78 100644 --- a/state/statedb.go +++ b/state/statedb.go @@ -88,7 +88,7 @@ func (self *StateDB) GetCode(addr common.Address) []byte { return nil } -func (self *StateDB) GetState(a common.Adress, b common.Hash) []byte { +func (self *StateDB) GetState(a common.Address, b common.Hash) []byte { stateObject := self.GetStateObject(a) if stateObject != nil { return stateObject.GetState(b).Bytes() @@ -150,14 +150,16 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) { self.db.Put(stateObject.CodeHash(), stateObject.code) } - self.trie.Update(stateObject.Address(), stateObject.RlpEncode()) + addr := stateObject.Address() + self.trie.Update(addr[:], stateObject.RlpEncode()) } // Delete the given state object and delete it from the state trie func (self *StateDB) DeleteStateObject(stateObject *StateObject) { - self.trie.Delete(stateObject.Address()) + addr := stateObject.Address() + self.trie.Delete(addr[:]) - delete(self.stateObjects, stateObject.Address().Str()) + delete(self.stateObjects, addr.Str()) } // Retrieve a state object given my the address. Nil if not found @@ -169,7 +171,7 @@ func (self *StateDB) GetStateObject(addr common.Address) *StateObject { return stateObject } - data := self.trie.Get(addr) + data := self.trie.Get(addr[:]) if len(data) == 0 { return nil } @@ -201,13 +203,13 @@ func (self *StateDB) NewStateObject(addr common.Address) *StateObject { statelogger.Debugf("(+) %x\n", addr) stateObject := NewStateObject(addr, self.db) - self.stateObjects[string(addr)] = stateObject + self.stateObjects[addr.Str()] = stateObject return stateObject } // Deprecated -func (self *StateDB) GetAccount(addr []byte) *StateObject { +func (self *StateDB) GetAccount(addr common.Address) *StateObject { return self.GetOrNewStateObject(addr) } From bfcd2cf132c2f1e5c1afe6d71e3d9d9dcee5017b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 17:27:23 +0100 Subject: [PATCH 08/78] block conversion --- core/types/block.go | 61 ++++++++++++++++++++-------------------- core/types/block_test.go | 19 +++++++++++++ core/types/bloom9.go | 6 ++-- core/types/common.go | 19 +++++++++++++ core/types/derive_sha.go | 6 ++-- state/dump.go | 1 - 6 files changed, 75 insertions(+), 37 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index fadf67086..9a97061b7 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -27,7 +27,7 @@ type Header struct { // Receipt sha ReceiptHash common.Hash // Bloom - Bloom [256]byte + Bloom Bloom // Difficulty for the current block Difficulty *big.Int // The block number @@ -73,28 +73,30 @@ func (self *Header) RlpData() interface{} { return self.rlpData(true) } -func (self *Header) Hash() []byte { - return crypto.Sha3(common.Encode(self.rlpData(true))) +func (self *Header) Hash() common.Hash { + return common.BytesToHash(crypto.Sha3(common.Encode(self.rlpData(true)))) } -func (self *Header) HashNoNonce() []byte { - return crypto.Sha3(common.Encode(self.rlpData(false))) +func (self *Header) HashNoNonce() common.Hash { + return common.BytesToHash(crypto.Sha3(common.Encode(self.rlpData(false)))) } type Block struct { - // Preset Hash for mock - HeaderHash []byte - ParentHeaderHash []byte - header *Header - uncles []*Header - transactions Transactions - Td *big.Int + // Preset Hash for mock (Tests) + HeaderHash common.Hash + ParentHeaderHash common.Hash + // ^^^^ ignore ^^^^ + + header *Header + uncles []*Header + transactions Transactions + Td *big.Int receipts Receipts Reward *big.Int } -func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce uint64, extra string) *Block { +func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block { header := &Header{ Root: root, ParentHash: parentHash, @@ -113,8 +115,7 @@ func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.I } func (self *Header) setNonce(nonce uint64) { - self.Nonce = make([]byte, 8) - binary.BigEndian.PutUint64(self.Nonce, nonce) + binary.BigEndian.PutUint64(self.Nonce[:], nonce) } func NewBlockWithHeader(header *Header) *Block { @@ -148,7 +149,7 @@ func (self *Block) Uncles() []*Header { func (self *Block) SetUncles(uncleHeaders []*Header) { self.uncles = uncleHeaders - self.header.UncleHash = crypto.Sha3(common.Encode(uncleHeaders)) + self.header.UncleHash = common.BytesToHash(crypto.Sha3(common.Encode(uncleHeaders))) } func (self *Block) Transactions() Transactions { @@ -196,23 +197,23 @@ func (self *Block) RlpDataForStorage() interface{} { } // Header accessors (add as you need them) -func (self *Block) Number() *big.Int { return self.header.Number } -func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } -func (self *Block) MixDigest() []byte { return self.header.MixDigest } +func (self *Block) Number() *big.Int { return self.header.Number } +func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } +func (self *Block) MixDigest() common.Hash { return self.header.MixDigest } func (self *Block) Nonce() uint64 { - return binary.BigEndian.Uint64(self.header.Nonce) + return binary.BigEndian.Uint64(self.header.Nonce[:]) } func (self *Block) SetNonce(nonce uint64) { self.header.setNonce(nonce) } -func (self *Block) Bloom() []byte { return self.header.Bloom } -func (self *Block) Coinbase() []byte { return self.header.Coinbase } +func (self *Block) Bloom() Bloom { return self.header.Bloom } +func (self *Block) Coinbase() common.Address { return self.header.Coinbase } func (self *Block) Time() int64 { return int64(self.header.Time) } func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } -func (self *Block) Root() []byte { return self.header.Root } -func (self *Block) SetRoot(root []byte) { self.header.Root = root } +func (self *Block) Root() common.Hash { return self.header.Root } +func (self *Block) SetRoot(root common.Hash) { self.header.Root = root } func (self *Block) Size() common.StorageSize { return common.StorageSize(len(common.Encode(self))) } func (self *Block) GetTransaction(i int) *Transaction { if len(self.transactions) > i { @@ -228,19 +229,19 @@ func (self *Block) GetUncle(i int) *Header { } // Implement pow.Block -func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } -func (self *Block) HashNoNonce() []byte { return self.header.HashNoNonce() } +func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } +func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() } -func (self *Block) Hash() []byte { - if self.HeaderHash != nil { +func (self *Block) Hash() common.Hash { + if (self.HeaderHash != common.Hash{}) { return self.HeaderHash } else { return self.header.Hash() } } -func (self *Block) ParentHash() []byte { - if self.ParentHeaderHash != nil { +func (self *Block) ParentHash() common.Hash { + if (self.ParentHeaderHash != common.Hash{}) { return self.ParentHeaderHash } else { return self.header.ParentHash diff --git a/core/types/block_test.go b/core/types/block_test.go index ab1254f4c..e2fa2cad2 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -1 +1,20 @@ package types + +import ( + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestConversion(t *testing.T) { + var ( + parent common.Hash + coinbase common.Address + hash common.Hash + ) + + block := NewBlock(parent, coinbase, hash, big.NewInt(0), 0, "") + fmt.Println(block) +} diff --git a/core/types/bloom9.go b/core/types/bloom9.go index af76f226f..e5b5e395f 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -3,18 +3,18 @@ package types import ( "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" ) -func CreateBloom(receipts Receipts) []byte { +func CreateBloom(receipts Receipts) Bloom { bin := new(big.Int) for _, receipt := range receipts { bin.Or(bin, LogsBloom(receipt.logs)) } - return common.LeftPadBytes(bin.Bytes(), 256) + return BytesToBloom(bin.Bytes()) } func LogsBloom(logs state.Logs) *big.Int { diff --git a/core/types/common.go b/core/types/common.go index 795374959..dd5dc00c8 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -5,3 +5,22 @@ import "math/big" type BlockProcessor interface { Process(*Block) (*big.Int, error) } + +type Bloom [256]byte + +func BytesToBloom(b []byte) Bloom { + var bloom Bloom + bloom.SetBytes(b) + return bloom +} + +func (b *Bloom) SetBytes(d []byte) { + if len(b) > len(d) { + panic("bloom bytes too big") + } + + // reverse loop + for i := len(d) - 1; i >= 0; i-- { + b[i] = b[i] + } +} diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go index 593a31f1c..0fc45a508 100644 --- a/core/types/derive_sha.go +++ b/core/types/derive_sha.go @@ -1,8 +1,8 @@ package types import ( - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" ) @@ -11,12 +11,12 @@ type DerivableList interface { GetRlp(i int) []byte } -func DeriveSha(list DerivableList) []byte { +func DeriveSha(list DerivableList) common.Hash { db, _ := ethdb.NewMemDatabase() trie := trie.New(nil, db) for i := 0; i < list.Len(); i++ { trie.Update(common.Encode(i), list.GetRlp(i)) } - return trie.Root() + return common.BytesToHash(trie.Root()) } diff --git a/state/dump.go b/state/dump.go index 2aafd1998..db05fae0c 100644 --- a/state/dump.go +++ b/state/dump.go @@ -28,7 +28,6 @@ func (self *StateDB) RawDump() World { it := self.trie.Iterator() for it.Next() { - fmt.Printf("%x\n", it.Key, len(it.Key)) stateObject := NewStateObjectFromBytes(common.BytesToAddress(it.Key), it.Value, self.db) account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)} From 64490897f3d7689fcd49dd3ae94b2b307f59b6cb Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 16 Mar 2015 17:27:24 +0100 Subject: [PATCH 09/78] crypto: add Sha3Hash --- crypto/crypto.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index bc72928ac..1f8dfcf32 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -16,10 +16,10 @@ import ( "errors" "code.google.com/p/go-uuid/uuid" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/sha3" - "github.com/ethereum/go-ethereum/common" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/ripemd160" ) @@ -37,6 +37,15 @@ func Sha3(data ...[]byte) []byte { return d.Sum(nil) } +func Sha3Hash(data ...[]byte) (h common.Hash) { + d := sha3.NewKeccak256() + for _, b := range data { + d.Write(b) + } + d.Sum(h[:]) + return h +} + // Creates an ethereum address given the bytes and the nonce func CreateAddress(b []byte, nonce uint64) []byte { return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:] From 16df850af2d2da0b7082e246d6f05eb1f1dc0706 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 16 Mar 2015 17:43:42 +0100 Subject: [PATCH 10/78] core/types: use common.{Hash,Address} in for transactions --- core/types/block.go | 5 +-- core/types/transaction.go | 89 +++++++++++---------------------------- 2 files changed, 26 insertions(+), 68 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 9a97061b7..80fc238aa 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "encoding/binary" "fmt" "math/big" @@ -156,9 +155,9 @@ func (self *Block) Transactions() Transactions { return self.transactions } -func (self *Block) Transaction(hash []byte) *Transaction { +func (self *Block) Transaction(hash common.Hash) *Transaction { for _, transaction := range self.transactions { - if bytes.Equal(hash, transaction.Hash()) { + if transaction.Hash() == hash { return transaction } } diff --git a/core/types/transaction.go b/core/types/transaction.go index dcd48af11..d55c5d5ae 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -2,13 +2,13 @@ package types import ( "bytes" - "crypto/ecdsa" "fmt" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" ) @@ -20,7 +20,7 @@ type Transaction struct { AccountNonce uint64 Price *big.Int GasLimit *big.Int - Recipient []byte + Recipient common.Address Amount *big.Int Payload []byte V byte @@ -28,31 +28,24 @@ type Transaction struct { } func NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction { - return NewTransactionMessage(nil, Amount, gasAmount, price, data) + return NewTransactionMessage(common.Address{}, Amount, gasAmount, price, data) } -func NewTransactionMessage(to []byte, Amount, gasAmount, price *big.Int, data []byte) *Transaction { +func NewTransactionMessage(to common.Address, Amount, gasAmount, price *big.Int, data []byte) *Transaction { return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data} } func NewTransactionFromBytes(data []byte) *Transaction { - tx := &Transaction{} - tx.RlpDecode(data) - + tx := new(Transaction) + rlp.Decode(bytes.NewReader(data), tx) return tx } -func NewTransactionFromAmount(val *common.Value) *Transaction { - tx := &Transaction{} - tx.RlpValueDecode(val) - - return tx -} - -func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} - - return crypto.Sha3(common.Encode(data)) +func (tx *Transaction) Hash() (a common.Hash) { + h := sha3.NewKeccak256() + rlp.Encode(h, []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}) + h.Sum(a[:]) + return a } func (self *Transaction) Data() []byte { @@ -79,11 +72,11 @@ func (self *Transaction) SetNonce(AccountNonce uint64) { self.AccountNonce = AccountNonce } -func (self *Transaction) From() []byte { +func (self *Transaction) From() common.Address { return self.sender() } -func (self *Transaction) To() []byte { +func (self *Transaction) To() common.Address { return self.Recipient } @@ -97,48 +90,31 @@ func (tx *Transaction) Curve() (v byte, r []byte, s []byte) { func (tx *Transaction) Signature(key []byte) []byte { hash := tx.Hash() - - sig, _ := secp256k1.Sign(hash, key) - + sig, _ := secp256k1.Sign(hash[:], key) return sig } func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() - v, r, s := tx.Curve() - sig := append(r, s...) sig = append(sig, v-27) //pubkey := crypto.Ecrecover(append(hash, sig...)) - pubkey, _ := secp256k1.RecoverPubkey(hash, sig) - + pubkey, _ := secp256k1.RecoverPubkey(hash[:], sig) return pubkey } -func (tx *Transaction) sender() []byte { +func (tx *Transaction) sender() (a common.Address) { pubkey := tx.PublicKey() // Validate the returned key. // Return nil if public key isn't in full format if len(pubkey) == 0 || pubkey[0] != 4 { - return nil + return a } - - return crypto.Sha3(pubkey[1:])[12:] -} - -// TODO: deprecate after new accounts & key stores are integrated -func (tx *Transaction) Sign(privk []byte) error { - - sig := tx.Signature(privk) - - tx.R = sig[:32] - tx.S = sig[32:64] - tx.V = sig[64] + 27 - - return nil + copy(a[:], crypto.Sha3(pubkey[1:])) + return a } func (tx *Transaction) SetSignatureValues(sig []byte) error { @@ -148,36 +124,17 @@ func (tx *Transaction) SetSignatureValues(sig []byte) error { return nil } -func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error { - return tx.Sign(crypto.FromECDSA(key)) -} - +// TODO: remove func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} - return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes()) } +// TODO: remove func (tx *Transaction) RlpEncode() []byte { return common.Encode(tx) } -func (tx *Transaction) RlpDecode(data []byte) { - rlp.Decode(bytes.NewReader(data), tx) -} - -func (tx *Transaction) RlpValueDecode(decoder *common.Value) { - tx.AccountNonce = decoder.Get(0).Uint() - tx.Price = decoder.Get(1).BigInt() - tx.GasLimit = decoder.Get(2).BigInt() - tx.Recipient = decoder.Get(3).Bytes() - tx.Amount = decoder.Get(4).BigInt() - tx.Payload = decoder.Get(5).Bytes() - tx.V = decoder.Get(6).Byte() - tx.R = decoder.Get(7).Bytes() - tx.S = decoder.Get(8).Bytes() -} - func (tx *Transaction) String() string { return fmt.Sprintf(` TX(%x) @@ -213,6 +170,7 @@ func (tx *Transaction) String() string { // Transaction slice type for basic sorting type Transactions []*Transaction +// TODO: remove func (self Transactions) RlpData() interface{} { // Marshal the transactions of this block enc := make([]interface{}, len(self)) @@ -223,6 +181,7 @@ func (self Transactions) RlpData() interface{} { return enc } + func (s Transactions) Len() int { return len(s) } func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s Transactions) GetRlp(i int) []byte { return common.Rlp(s[i]) } From 91b0b14845750c81466880f5f877fe3fcbd03b09 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 18:42:18 +0100 Subject: [PATCH 11/78] converted vm --- common/types.go | 45 +++++++++++++++++++++--------------- core/types/block_test.go | 5 ++-- state/log.go | 14 ++++++++---- vm/context.go | 8 +++---- vm/environment.go | 12 +++++----- vm/vm.go | 49 +++++++++++++++++++++------------------- 6 files changed, 75 insertions(+), 58 deletions(-) diff --git a/common/types.go b/common/types.go index 3dc4500b3..267077f4f 100644 --- a/common/types.go +++ b/common/types.go @@ -1,8 +1,16 @@ package common -import "fmt" +import "math/big" -type Hash [32]byte +const ( + hashLength = 32 + addressLength = 20 +) + +type ( + Hash [hashLength]byte + Address [addressLength]byte +) var ( zeroHash Hash @@ -15,25 +23,19 @@ func BytesToHash(b []byte) Hash { return h } func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } - -func BytesToAddress(b []byte) Address { - var a Address - a.SetBytes(b) - return a -} -func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } +func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } // Don't use the default 'String' method in case we want to overwrite // Get the string representation of the underlying hash -func (h Hash) Str() string { - return string(h[:]) -} +func (h Hash) Str() string { return string(h[:]) } +func (h Hash) Bytes() []byte { return h[:] } +func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) } // Sets the hash to the value of b. If b is larger than len(h) it will panic func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { - panic(fmt.Sprintf("unable to set bytes. too big = %d", len(b))) + b = b[len(b)-hashLength:] } // reverse loop @@ -52,17 +54,24 @@ func (h *Hash) Set(other Hash) { } } -type Address [20]byte +/////////// Address +func BytesToAddress(b []byte) Address { + var a Address + a.SetBytes(b) + return a +} +func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } +func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } // Get the string representation of the underlying address -func (a Address) Str() string { - return string(a[:]) -} +func (a Address) Str() string { return string(a[:]) } +func (a Address) Bytes() []byte { return a[:] } +func (a Address) Big() *big.Int { return Bytes2Big(a[:]) } // Sets the address to the value of b. If b is larger than len(a) it will panic func (a *Address) SetBytes(b []byte) { if len(b) > len(a) { - panic(fmt.Sprintf("unable to set bytes. too big = %d", len(b))) + b = b[len(b)-addressLength:] } // reverse loop diff --git a/core/types/block_test.go b/core/types/block_test.go index e2fa2cad2..16ba3043f 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -1,13 +1,13 @@ package types import ( - "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/common" ) +// XXX Tests doesn't really do anything. This tests exists while working on the fixed size conversions func TestConversion(t *testing.T) { var ( parent common.Hash @@ -15,6 +15,5 @@ func TestConversion(t *testing.T) { hash common.Hash ) - block := NewBlock(parent, coinbase, hash, big.NewInt(0), 0, "") - fmt.Println(block) + NewBlock(parent, coinbase, hash, big.NewInt(0), 0, "") } diff --git a/state/log.go b/state/log.go index a0859aaf2..8b8bf2204 100644 --- a/state/log.go +++ b/state/log.go @@ -9,7 +9,7 @@ import ( type Log interface { common.RlpEncodable - Address() []byte + Address() common.Address Topics() [][]byte Data() []byte @@ -17,17 +17,17 @@ type Log interface { } type StateLog struct { - address []byte + address common.Address topics [][]byte data []byte number uint64 } -func NewLog(address []byte, topics [][]byte, data []byte, number uint64) *StateLog { +func NewLog(address common.Address, topics [][]byte, data []byte, number uint64) *StateLog { return &StateLog{address, topics, data, number} } -func (self *StateLog) Address() []byte { +func (self *StateLog) Address() common.Address { return self.address } @@ -43,7 +43,12 @@ func (self *StateLog) Number() uint64 { return self.number } +/* func NewLogFromValue(decoder *common.Value) *StateLog { + var extlog struct { + + } + log := &StateLog{ address: decoder.Get(0).Bytes(), data: decoder.Get(2).Bytes(), @@ -56,6 +61,7 @@ func NewLogFromValue(decoder *common.Value) *StateLog { return log } +*/ func (self *StateLog) RlpData() interface{} { return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data} diff --git a/vm/context.go b/vm/context.go index 6edde0824..93a0102d4 100644 --- a/vm/context.go +++ b/vm/context.go @@ -9,7 +9,7 @@ import ( type ContextRef interface { ReturnGas(*big.Int, *big.Int) - Address() []byte + Address() common.Address SetCode([]byte) } @@ -18,7 +18,7 @@ type Context struct { self ContextRef Code []byte - CodeAddr []byte + CodeAddr common.Address value, Gas, UsedGas, Price *big.Int @@ -100,7 +100,7 @@ func (c *Context) ReturnGas(gas, price *big.Int) { /* * Set / Get */ -func (c *Context) Address() []byte { +func (c *Context) Address() common.Address { return c.self.Address() } @@ -108,7 +108,7 @@ func (self *Context) SetCode(code []byte) { self.Code = code } -func (self *Context) SetCallCode(addr, code []byte) { +func (self *Context) SetCallCode(addr common.Address, code []byte) { self.Code = code self.CodeAddr = addr } diff --git a/vm/environment.go b/vm/environment.go index 83faaa23e..a53411b23 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -12,7 +12,7 @@ import ( type Environment interface { State() *state.StateDB - Origin() []byte + Origin() common.Address BlockNumber() *big.Int GetHash(n uint64) []byte Coinbase() []byte @@ -27,9 +27,9 @@ type Environment interface { Depth() int SetDepth(i int) - Call(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) - CallCode(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) - Create(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) + Call(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) + CallCode(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) + Create(me ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) } type Account interface { @@ -53,13 +53,13 @@ func Transfer(from, to Account, amount *big.Int) error { } type Log struct { - address []byte + address common.Address topics [][]byte data []byte log uint64 } -func (self *Log) Address() []byte { +func (self *Log) Address() common.Address { return self.address } diff --git a/vm/vm.go b/vm/vm.go index 4d9e88e1a..5043babcd 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -4,8 +4,8 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" ) @@ -44,7 +44,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { price = context.Price ) - self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl() + self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl() if self.Recoverable { // Recover from any require exception @@ -62,7 +62,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { }() } - if p := Precompiled[string(context.CodeAddr)]; p != nil { + if p := Precompiled[context.CodeAddr.Str()]; p != nil { return self.RunPrecompiled(p, callData, context) } @@ -394,11 +394,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => (%v) %x", size, data) // 0x30 range case ADDRESS: - stack.push(common.BigD(context.Address())) + stack.push(common.Bytes2Big(context.Address().Bytes())) self.Printf(" => %x", context.Address()) case BALANCE: - addr := stack.pop().Bytes() + addr := common.BigToAddress(stack.pop()) balance := statedb.GetBalance(addr) stack.push(balance) @@ -407,12 +407,12 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case ORIGIN: origin := self.env.Origin() - stack.push(common.BigD(origin)) + stack.push(origin.Big()) self.Printf(" => %x", origin) case CALLER: caller := context.caller.Address() - stack.push(common.BigD(caller)) + stack.push(common.Bytes2Big(caller.Bytes())) self.Printf(" => %x", caller) case CALLVALUE: @@ -464,7 +464,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { - addr := stack.pop().Bytes() + addr := common.BigToAddress(stack.pop()) code = statedb.GetCode(addr) } else { @@ -478,7 +478,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case CODECOPY, EXTCODECOPY: var code []byte if op == EXTCODECOPY { - code = statedb.GetCode(stack.pop().Bytes()) + addr := common.BigToAddress(stack.pop()) + code = statedb.GetCode(addr) } else { code = context.Code } @@ -593,16 +594,18 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => [%v] 0x%x", off, val) case SLOAD: - loc := stack.pop() - val := common.BigD(statedb.GetState(context.Address(), loc.Bytes())) + loc := common.BigToHash(stack.pop()) + val := common.Bytes2Big(statedb.GetState(context.Address(), loc)) stack.push(val) - self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) case SSTORE: - loc, val := stack.pop(), stack.pop() - statedb.SetState(context.Address(), loc.Bytes(), val) + loc := common.BigToHash(stack.pop()) + val := stack.pop() - self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + statedb.SetState(context.Address(), loc, val) + + self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) case JUMP: jump(pc, stack.pop()) @@ -635,12 +638,12 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { offset, size = stack.pop(), stack.pop() input = mem.Get(offset.Int64(), size.Int64()) gas = new(big.Int).Set(context.Gas) - addr []byte + addr common.Address ) self.Endl() context.UseGas(context.Gas) - ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value) + ret, suberr, ref := self.env.Create(context, input, gas, price, value) if suberr != nil { stack.push(common.BigFalse) @@ -655,7 +658,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { } addr = ref.Address() - stack.push(common.BigD(addr)) + stack.push(addr.Big()) } @@ -669,7 +672,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { // pop return size and offset retOffset, retSize := stack.pop(), stack.pop() - address := common.Address(addr.Bytes()) + address := common.BigToAddress(addr) self.Printf(" => %x", address).Endl() // Get the arguments from the memory @@ -707,10 +710,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { return context.Return(ret), nil case SUICIDE: - receiver := statedb.GetOrNewStateObject(stack.pop().Bytes()) + receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop())) balance := statedb.GetBalance(context.Address()) - self.Printf(" => (%x) %v", receiver.Address()[:4], balance) + self.Printf(" => (%x) %v", receiver.Address().Bytes()[:4], balance) receiver.AddBalance(balance) @@ -770,7 +773,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo var g *big.Int y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] - val := statedb.GetState(context.Address(), x.Bytes()) + val := statedb.GetState(context.Address(), common.BigToHash(x)) if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 g = GasStorageAdd @@ -822,7 +825,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo gas.Add(gas, stack.data[stack.len()-1]) if op == CALL { - if self.env.State().GetStateObject(stack.data[stack.len()-2].Bytes()) == nil { + if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { gas.Add(gas, GasCallNewAccount) } } From 4e181c5764b78193705f91d3220710bb63b8962f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 21:46:47 +0100 Subject: [PATCH 12/78] Moved gas --- vm/common.go | 78 +++++++++++----------------------------------------- vm/gas.go | 49 +++++++++++++++++++++++++++++++++ vm/vm.go | 4 --- 3 files changed, 65 insertions(+), 66 deletions(-) diff --git a/vm/common.go b/vm/common.go index 1f07ec8a2..cedc0f309 100644 --- a/vm/common.go +++ b/vm/common.go @@ -18,8 +18,23 @@ type Type byte const ( StdVmTy Type = iota JitVmTy - MaxVmTy + + MaxCallDepth = 1025 + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 +) + +var ( + Pow256 = common.BigPow(2, 256) + + U256 = common.U256 + S256 = common.S256 + + Zero = common.Big0 + + max = big.NewInt(math.MaxInt64) ) func NewVm(env Environment) VirtualMachine { @@ -34,67 +49,6 @@ func NewVm(env Environment) VirtualMachine { } } -var ( - GasQuickStep = big.NewInt(2) - GasFastestStep = big.NewInt(3) - GasFastStep = big.NewInt(5) - GasMidStep = big.NewInt(8) - GasSlowStep = big.NewInt(10) - GasExtStep = big.NewInt(20) - - GasStorageGet = big.NewInt(50) - GasStorageAdd = big.NewInt(20000) - GasStorageMod = big.NewInt(5000) - GasLogBase = big.NewInt(375) - GasLogTopic = big.NewInt(375) - GasLogByte = big.NewInt(8) - GasCreate = big.NewInt(32000) - GasCreateByte = big.NewInt(200) - GasCall = big.NewInt(40) - GasCallValueTransfer = big.NewInt(9000) - GasStipend = big.NewInt(2300) - GasCallNewAccount = big.NewInt(25000) - GasReturn = big.NewInt(0) - GasStop = big.NewInt(0) - GasJumpDest = big.NewInt(1) - - RefundStorage = big.NewInt(15000) - RefundSuicide = big.NewInt(24000) - - GasMemWord = big.NewInt(3) - GasQuadCoeffDenom = big.NewInt(512) - GasContractByte = big.NewInt(200) - GasTransaction = big.NewInt(21000) - GasTxDataNonzeroByte = big.NewInt(68) - GasTxDataZeroByte = big.NewInt(4) - GasTx = big.NewInt(21000) - GasExp = big.NewInt(10) - GasExpByte = big.NewInt(10) - - GasSha3Base = big.NewInt(30) - GasSha3Word = big.NewInt(6) - GasSha256Base = big.NewInt(60) - GasSha256Word = big.NewInt(12) - GasRipemdBase = big.NewInt(600) - GasRipemdWord = big.NewInt(12) - GasEcrecover = big.NewInt(3000) - GasIdentityBase = big.NewInt(15) - GasIdentityWord = big.NewInt(3) - GasCopyWord = big.NewInt(3) - - Pow256 = common.BigPow(2, 256) - - LogTyPretty byte = 0x1 - LogTyDiff byte = 0x2 - - U256 = common.U256 - S256 = common.S256 - - Zero = common.Big0 -) - -const MaxCallDepth = 1025 - func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(common.Big0) == 0 { return common.Big0 diff --git a/vm/gas.go b/vm/gas.go index a19afeb67..c4d5e4c4e 100644 --- a/vm/gas.go +++ b/vm/gas.go @@ -7,6 +7,55 @@ type req struct { gas *big.Int } +var ( + GasQuickStep = big.NewInt(2) + GasFastestStep = big.NewInt(3) + GasFastStep = big.NewInt(5) + GasMidStep = big.NewInt(8) + GasSlowStep = big.NewInt(10) + GasExtStep = big.NewInt(20) + + GasStorageGet = big.NewInt(50) + GasStorageAdd = big.NewInt(20000) + GasStorageMod = big.NewInt(5000) + GasLogBase = big.NewInt(375) + GasLogTopic = big.NewInt(375) + GasLogByte = big.NewInt(8) + GasCreate = big.NewInt(32000) + GasCreateByte = big.NewInt(200) + GasCall = big.NewInt(40) + GasCallValueTransfer = big.NewInt(9000) + GasStipend = big.NewInt(2300) + GasCallNewAccount = big.NewInt(25000) + GasReturn = big.NewInt(0) + GasStop = big.NewInt(0) + GasJumpDest = big.NewInt(1) + + RefundStorage = big.NewInt(15000) + RefundSuicide = big.NewInt(24000) + + GasMemWord = big.NewInt(3) + GasQuadCoeffDenom = big.NewInt(512) + GasContractByte = big.NewInt(200) + GasTransaction = big.NewInt(21000) + GasTxDataNonzeroByte = big.NewInt(68) + GasTxDataZeroByte = big.NewInt(4) + GasTx = big.NewInt(21000) + GasExp = big.NewInt(10) + GasExpByte = big.NewInt(10) + + GasSha3Base = big.NewInt(30) + GasSha3Word = big.NewInt(6) + GasSha256Base = big.NewInt(60) + GasSha256Word = big.NewInt(12) + GasRipemdBase = big.NewInt(600) + GasRipemdWord = big.NewInt(12) + GasEcrecover = big.NewInt(3000) + GasIdentityBase = big.NewInt(15) + GasIdentityWord = big.NewInt(3) + GasCopyWord = big.NewInt(3) +) + var _baseCheck = map[OpCode]req{ // Req stack Gas price ADD: {2, GasFastestStep}, diff --git a/vm/vm.go b/vm/vm.go index 5043babcd..4ef888e36 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -33,10 +33,7 @@ func New(env Environment) *Vm { } func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { - //func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { self.env.SetDepth(self.env.Depth() + 1) - - //context := NewContext(caller, me, code, gas, price) var ( caller = context.caller code = context.Code @@ -57,7 +54,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { ret = context.Return(nil) err = fmt.Errorf("%v", r) - } }() } From 843db4978e876674ca111706880a58c84202880d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 23:10:26 +0100 Subject: [PATCH 13/78] updated blockpool --- blockpool/blockpool.go | 51 +++++++++++++++++++-------------------- blockpool/peers.go | 49 ++++++++++++++++++------------------- blockpool/section.go | 15 ++++++------ common/types.go | 3 +++ core/types/block.go | 6 ++--- core/types/bloom9.go | 6 ++--- core/types/receipt.go | 36 +++++++++++++-------------- state/log.go | 20 ++++++++++----- tests/blocktest.go | 55 +++++++++++++++++++++++++++++++----------- vm/environment.go | 12 +++++++-- vm/vm.go | 4 +-- 11 files changed, 151 insertions(+), 106 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index bc998cd7b..c5af481a7 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -1,12 +1,12 @@ package blockpool import ( - "bytes" "fmt" "math/big" "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" ethlogger "github.com/ethereum/go-ethereum/logger" @@ -101,7 +101,7 @@ func (self *Config) init() { // node is the basic unit of the internal model of block chain/tree in the blockpool type node struct { lock sync.RWMutex - hash []byte + hash common.Hash block *types.Block hashBy string blockBy string @@ -123,7 +123,7 @@ type BlockPool struct { Config *Config // the minimal interface with blockchain - hasBlock func(hash []byte) bool + hasBlock func(hash common.Hash) bool insertChain func(types.Blocks) error verifyPoW func(pow.Block) bool @@ -133,7 +133,7 @@ type BlockPool struct { lock sync.RWMutex chainLock sync.RWMutex // alloc-easy pool of hash slices - hashSlicePool chan [][]byte + hashSlicePool chan []common.Hash status *status @@ -144,7 +144,7 @@ type BlockPool struct { // public constructor func New( - hasBlock func(hash []byte) bool, + hasBlock func(hash common.Hash) bool, insertChain func(types.Blocks) error, verifyPoW func(pow.Block) bool, ) *BlockPool { @@ -176,7 +176,7 @@ func (self *BlockPool) Start() { } self.Config.init() - self.hashSlicePool = make(chan [][]byte, 150) + self.hashSlicePool = make(chan []common.Hash, 150) self.status = newStatus() self.quit = make(chan bool) self.pool = make(map[string]*entry) @@ -261,14 +261,13 @@ Peer info is currently not persisted across disconnects (or sessions) */ func (self *BlockPool) AddPeer( - td *big.Int, currentBlockHash []byte, + td *big.Int, currentBlockHash common.Hash, peerId string, - requestBlockHashes func([]byte) error, - requestBlocks func([][]byte) error, + requestBlockHashes func(common.Hash) error, + requestBlocks func([]common.Hash) error, peerError func(*errs.Error), ) (best bool) { - return self.peers.addPeer(td, currentBlockHash, peerId, requestBlockHashes, requestBlocks, peerError) } @@ -289,7 +288,7 @@ launches all block request processes on each chain section the first argument is an iterator function. Using this block hashes are decoded from the rlp message payload on demand. As a result, AddBlockHashes needs to run synchronously for one peer since the message is discarded if the caller thread returns. */ -func (self *BlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) { +func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId string) { bestpeer, best := self.peers.getPeer(peerId) if !best { @@ -306,7 +305,7 @@ func (self *BlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) self.status.lock.Unlock() var n int - var hash []byte + var hash common.Hash var ok, headSection, peerswitch bool var sec, child, parent *section var entry *entry @@ -318,7 +317,7 @@ func (self *BlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) plog.Debugf("AddBlockHashes: peer <%s> starting from [%s] (peer head: %s)", peerId, hex(bestpeer.parentHash), hex(bestpeer.currentBlockHash)) // first check if we are building the head section of a peer's chain - if bytes.Equal(bestpeer.parentHash, hash) { + if bestpeer.parentHash == hash { if self.hasBlock(bestpeer.currentBlockHash) { return } @@ -561,7 +560,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { entry := self.get(hash) // a peer's current head block is appearing the first time - if bytes.Equal(hash, sender.currentBlockHash) { + if hash == sender.currentBlockHash { if sender.currentBlock == nil { plog.Debugf("AddBlock: add head block %s for peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) sender.setChainInfoFromBlock(block) @@ -664,7 +663,7 @@ LOOP: plog.DebugDetailf("activateChain: section [%s] activated by peer <%s>", sectionhex(sec), p.id) sec.activate(p) if i > 0 && connected != nil { - connected[string(sec.top.hash)] = sec + connected[sec.top.hash.Str()] = sec } /* we need to relink both complete and incomplete sections @@ -696,7 +695,7 @@ LOOP: // must run in separate go routine, otherwise // switchpeer -> activateChain -> activate deadlocks on section process select and peers.lock -func (self *BlockPool) requestBlocks(attempts int, hashes [][]byte) { +func (self *BlockPool) requestBlocks(attempts int, hashes []common.Hash) { self.wg.Add(1) go func() { self.peers.requestBlocks(attempts, hashes) @@ -718,16 +717,16 @@ func (self *BlockPool) getChild(sec *section) *section { } // accessor and setter for entries in the pool -func (self *BlockPool) get(hash []byte) *entry { +func (self *BlockPool) get(hash common.Hash) *entry { self.lock.RLock() defer self.lock.RUnlock() - return self.pool[string(hash)] + return self.pool[hash.Str()] } -func (self *BlockPool) set(hash []byte, e *entry) { +func (self *BlockPool) set(hash common.Hash, e *entry) { self.lock.Lock() defer self.lock.Unlock() - self.pool[string(hash)] = e + self.pool[hash.Str()] = e } func (self *BlockPool) remove(sec *section) { @@ -736,7 +735,7 @@ func (self *BlockPool) remove(sec *section) { defer self.lock.Unlock() for _, node := range sec.nodes { - delete(self.pool, string(node.hash)) + delete(self.pool, node.hash.Str()) } if sec.initialised && sec.poolRootIndex != 0 { self.status.lock.Lock() @@ -745,17 +744,17 @@ func (self *BlockPool) remove(sec *section) { } } -func (self *BlockPool) getHashSlice() (s [][]byte) { +func (self *BlockPool) getHashSlice() (s []common.Hash) { select { case s = <-self.hashSlicePool: default: - s = make([][]byte, self.Config.BlockBatchSize) + s = make([]common.Hash, self.Config.BlockBatchSize) } return } // Return returns a Client to the pool. -func (self *BlockPool) putHashSlice(s [][]byte) { +func (self *BlockPool) putHashSlice(s []common.Hash) { if len(s) == self.Config.BlockBatchSize { select { case self.hashSlicePool <- s: @@ -765,8 +764,8 @@ func (self *BlockPool) putHashSlice(s [][]byte) { } // pretty prints hash (byte array) with first 4 bytes in hex -func hex(hash []byte) (name string) { - if hash == nil { +func hex(hash common.Hash) (name string) { + if (hash == common.Hash{}) { name = "" } else { name = fmt.Sprintf("%x", hash[:4]) diff --git a/blockpool/peers.go b/blockpool/peers.go index 5f4889792..d94d6ac46 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -1,16 +1,15 @@ package blockpool import ( - "bytes" "math/big" "math/rand" "sort" "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" - "github.com/ethereum/go-ethereum/common" ) type peer struct { @@ -18,20 +17,20 @@ type peer struct { // last known blockchain status td *big.Int - currentBlockHash []byte + currentBlockHash common.Hash currentBlock *types.Block - parentHash []byte + parentHash common.Hash headSection *section id string // peer callbacks - requestBlockHashes func([]byte) error - requestBlocks func([][]byte) error + requestBlockHashes func(common.Hash) error + requestBlocks func([]common.Hash) error peerError func(*errs.Error) errors *errs.Errors - sections [][]byte + sections []common.Hash // channels to push new head block and head section for peer a currentBlockC chan *types.Block @@ -66,10 +65,10 @@ type peers struct { // peer constructor func (self *peers) newPeer( td *big.Int, - currentBlockHash []byte, + currentBlockHash common.Hash, id string, - requestBlockHashes func([]byte) error, - requestBlocks func([][]byte) error, + requestBlockHashes func(common.Hash) error, + requestBlocks func([]common.Hash) error, peerError func(*errs.Error), ) (p *peer) { @@ -107,7 +106,7 @@ func (self *peer) addError(code int, format string, params ...interface{}) { self.peerError(err) } -func (self *peer) setChainInfo(td *big.Int, c []byte) { +func (self *peer) setChainInfo(td *big.Int, c common.Hash) { self.lock.Lock() defer self.lock.Unlock() @@ -115,7 +114,7 @@ func (self *peer) setChainInfo(td *big.Int, c []byte) { self.currentBlockHash = c self.currentBlock = nil - self.parentHash = nil + self.parentHash = common.Hash{} self.headSection = nil } @@ -139,7 +138,7 @@ func (self *peer) setChainInfoFromBlock(block *types.Block) { }() } -func (self *peers) requestBlocks(attempts int, hashes [][]byte) { +func (self *peers) requestBlocks(attempts int, hashes []common.Hash) { // distribute block request among known peers self.lock.RLock() defer self.lock.RUnlock() @@ -178,18 +177,18 @@ func (self *peers) requestBlocks(attempts int, hashes [][]byte) { // returns true iff peer is promoted as best peer in the pool func (self *peers) addPeer( td *big.Int, - currentBlockHash []byte, + currentBlockHash common.Hash, id string, - requestBlockHashes func([]byte) error, - requestBlocks func([][]byte) error, + requestBlockHashes func(common.Hash) error, + requestBlocks func([]common.Hash) error, peerError func(*errs.Error), ) (best bool) { - var previousBlockHash []byte + var previousBlockHash common.Hash self.lock.Lock() p, found := self.peers[id] if found { - if !bytes.Equal(p.currentBlockHash, currentBlockHash) { + if p.currentBlockHash != currentBlockHash { previousBlockHash = p.currentBlockHash plog.Debugf("addPeer: Update peer <%s> with td %v and current block %s (was %v)", id, td, hex(currentBlockHash), hex(previousBlockHash)) p.setChainInfo(td, currentBlockHash) @@ -221,7 +220,7 @@ func (self *peers) addPeer( // new block update for active current best peer -> request hashes plog.Debugf("addPeer: <%s> already the best peer. Request new head section info from %s", id, hex(currentBlockHash)) - if previousBlockHash != nil { + if (previousBlockHash != common.Hash{}) { if entry := self.bp.get(previousBlockHash); entry != nil { p.headSectionC <- nil self.bp.activateChain(entry.section, p, nil) @@ -318,15 +317,15 @@ func (self *BlockPool) switchPeer(oldp, newp *peer) { } var connected = make(map[string]*section) - var sections [][]byte + var sections []common.Hash for _, hash := range newp.sections { plog.DebugDetailf("activate chain starting from section [%s]", hex(hash)) // if section not connected (ie, top of a contiguous sequence of sections) - if connected[string(hash)] == nil { + if connected[hash.Str()] == nil { // if not deleted, then reread from pool (it can be orphaned top half of a split section) if entry := self.get(hash); entry != nil { self.activateChain(entry.section, newp, connected) - connected[string(hash)] = entry.section + connected[hash.Str()] = entry.section sections = append(sections, hash) } } @@ -396,7 +395,7 @@ func (self *peer) getCurrentBlock(currentBlock *types.Block) { plog.DebugDetailf("HeadSection: <%s> head block %s found in blockpool", self.id, hex(self.currentBlockHash)) } else { plog.DebugDetailf("HeadSection: <%s> head block %s not found... requesting it", self.id, hex(self.currentBlockHash)) - self.requestBlocks([][]byte{self.currentBlockHash}) + self.requestBlocks([]common.Hash{self.currentBlockHash}) self.blocksRequestTimer = time.After(self.bp.Config.BlocksRequestInterval) return } @@ -427,9 +426,9 @@ func (self *peer) getBlockHashes() { self.addError(ErrInvalidBlock, "%v", err) self.bp.status.badPeers[self.id]++ } else { - headKey := string(self.parentHash) + headKey := self.parentHash.Str() height := self.bp.status.chain[headKey] + 1 - self.bp.status.chain[string(self.currentBlockHash)] = height + self.bp.status.chain[self.currentBlockHash.Str()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height } diff --git a/blockpool/section.go b/blockpool/section.go index 03c4f5cc6..c73aaa6df 100644 --- a/blockpool/section.go +++ b/blockpool/section.go @@ -4,6 +4,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -27,9 +28,9 @@ type section struct { nodes []*node peer *peer - parentHash []byte + parentHash common.Hash - blockHashes [][]byte + blockHashes []common.Hash poolRootIndex int @@ -115,7 +116,7 @@ func (self *section) addSectionToBlockChain(p *peer) { break } self.poolRootIndex-- - keys = append(keys, string(node.hash)) + keys = append(keys, node.hash.Str()) blocks = append(blocks, block) } @@ -166,9 +167,9 @@ func (self *section) addSectionToBlockChain(p *peer) { self.bp.status.lock.Lock() if err == nil { - headKey := string(blocks[0].ParentHash()) + headKey := blocks[0].ParentHash().Str() height := self.bp.status.chain[headKey] + len(blocks) - self.bp.status.chain[string(blocks[len(blocks)-1].Hash())] = height + self.bp.status.chain[blocks[len(blocks)-1].Hash().Str()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height } @@ -316,7 +317,7 @@ LOOP: self.addSectionToBlockChain(self.peer) } } else { - if self.parentHash == nil && n == self.bottom { + if (self.parentHash == common.Hash{}) && n == self.bottom { self.parentHash = block.ParentHash() plog.DebugDetailf("[%s] got parent head block hash %s...checking", sectionhex(self), hex(self.parentHash)) self.blockHashesRequest() @@ -456,7 +457,7 @@ func (self *section) blockHashesRequest() { // a demoted peer's fork will be chosen over the best peer's chain // because relinking the correct chain (activateChain) is overwritten here in // demoted peer's section process just before the section is put to idle mode - if self.parentHash != nil { + if (self.parentHash != common.Hash{}) { if parent := self.bp.get(self.parentHash); parent != nil { parentSection = parent.section plog.DebugDetailf("[%s] blockHashesRequest: parent section [%s] linked\n", sectionhex(self), sectionhex(parentSection)) diff --git a/common/types.go b/common/types.go index 267077f4f..9729378e8 100644 --- a/common/types.go +++ b/common/types.go @@ -24,6 +24,7 @@ func BytesToHash(b []byte) Hash { } func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } +func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } // Don't use the default 'String' method in case we want to overwrite @@ -62,11 +63,13 @@ func BytesToAddress(b []byte) Address { } func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } +func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } // Get the string representation of the underlying address func (a Address) Str() string { return string(a[:]) } func (a Address) Bytes() []byte { return a[:] } func (a Address) Big() *big.Int { return Bytes2Big(a[:]) } +func (a Address) Hash() Hash { return BytesToHash(a[:]) } // Sets the address to the value of b. If b is larger than len(a) it will panic func (a *Address) SetBytes(b []byte) { diff --git a/core/types/block.go b/core/types/block.go index 80fc238aa..aca23aa04 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -106,14 +106,14 @@ func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, GasUsed: new(big.Int), GasLimit: new(big.Int), } - header.setNonce(nonce) + header.SetNonce(nonce) block := &Block{header: header, Reward: new(big.Int)} return block } -func (self *Header) setNonce(nonce uint64) { +func (self *Header) SetNonce(nonce uint64) { binary.BigEndian.PutUint64(self.Nonce[:], nonce) } @@ -203,7 +203,7 @@ func (self *Block) Nonce() uint64 { return binary.BigEndian.Uint64(self.header.Nonce[:]) } func (self *Block) SetNonce(nonce uint64) { - self.header.setNonce(nonce) + self.header.SetNonce(nonce) } func (self *Block) Bloom() Bloom { return self.header.Bloom } diff --git a/core/types/bloom9.go b/core/types/bloom9.go index e5b5e395f..b3cab86a0 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -20,15 +20,15 @@ func CreateBloom(receipts Receipts) Bloom { func LogsBloom(logs state.Logs) *big.Int { bin := new(big.Int) for _, log := range logs { - data := make([][]byte, len(log.Topics())+1) - data[0] = log.Address() + data := make([]common.Hash, len(log.Topics())+1) + data[0] = log.Address().Hash() for i, topic := range log.Topics() { data[i+1] = topic } for _, b := range data { - bin.Or(bin, common.BigD(bloom9(crypto.Sha3(b)).Bytes())) + bin.Or(bin, common.BigD(bloom9(crypto.Sha3(b[:])).Bytes())) } } diff --git a/core/types/receipt.go b/core/types/receipt.go index be14d0e0e..d0cb41e25 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -3,9 +3,11 @@ package types import ( "bytes" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) @@ -20,34 +22,26 @@ func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt { return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumalativeGasUsed)} } -func NewRecieptFromValue(val *common.Value) *Receipt { - r := &Receipt{} - r.RlpValueDecode(val) - - return r -} - func (self *Receipt) SetLogs(logs state.Logs) { self.logs = logs } -func (self *Receipt) RlpValueDecode(decoder *common.Value) { - self.PostState = decoder.Get(0).Bytes() - self.CumulativeGasUsed = decoder.Get(1).BigInt() - self.Bloom = decoder.Get(2).Bytes() - - it := decoder.Get(3).NewIterator() - for it.Next() { - self.logs = append(self.logs, state.NewLogFromValue(it.Value())) - } +func (self *Receipt) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs}) } +/* func (self *Receipt) RlpData() interface{} { return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} } +*/ func (self *Receipt) RlpEncode() []byte { - return common.Encode(self.RlpData()) + bytes, err := rlp.EncodeToBytes(self) + if err != nil { + fmt.Println("TMP -- RECEIPT ENCODE ERROR", err) + } + return bytes } func (self *Receipt) Cmp(other *Receipt) bool { @@ -64,6 +58,7 @@ func (self *Receipt) String() string { type Receipts []*Receipt +/* func (self Receipts) RlpData() interface{} { data := make([]interface{}, len(self)) for i, receipt := range self { @@ -72,9 +67,14 @@ func (self Receipts) RlpData() interface{} { return data } +*/ func (self Receipts) RlpEncode() []byte { - return common.Encode(self.RlpData()) + bytes, err := rlp.EncodeToBytes(self) + if err != nil { + fmt.Println("TMP -- RECEIPTS ENCODE ERROR", err) + } + return bytes } func (self Receipts) Len() int { return len(self) } diff --git a/state/log.go b/state/log.go index 8b8bf2204..f8aa4c08c 100644 --- a/state/log.go +++ b/state/log.go @@ -2,15 +2,15 @@ package state import ( "fmt" + "io" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) type Log interface { - common.RlpEncodable - Address() common.Address - Topics() [][]byte + Topics() []common.Hash Data() []byte Number() uint64 @@ -18,12 +18,12 @@ type Log interface { type StateLog struct { address common.Address - topics [][]byte + topics []common.Hash data []byte number uint64 } -func NewLog(address common.Address, topics [][]byte, data []byte, number uint64) *StateLog { +func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *StateLog { return &StateLog{address, topics, data, number} } @@ -31,7 +31,7 @@ func (self *StateLog) Address() common.Address { return self.address } -func (self *StateLog) Topics() [][]byte { +func (self *StateLog) Topics() []common.Hash { return self.topics } @@ -63,9 +63,15 @@ func NewLogFromValue(decoder *common.Value) *StateLog { } */ +func (self *StateLog) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.address, self.topics, self.data}) +} + +/* func (self *StateLog) RlpData() interface{} { return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data} } +*/ func (self *StateLog) String() string { return fmt.Sprintf(`log: %x %x %x`, self.address, self.topics, self.data) @@ -73,6 +79,7 @@ func (self *StateLog) String() string { type Logs []Log +/* func (self Logs) RlpData() interface{} { data := make([]interface{}, len(self)) for i, log := range self { @@ -81,6 +88,7 @@ func (self Logs) RlpData() interface{} { return data } +*/ func (self Logs) String() (ret string) { for _, log := range self { diff --git a/tests/blocktest.go b/tests/blocktest.go index 0b923f08b..e4d001089 100644 --- a/tests/blocktest.go +++ b/tests/blocktest.go @@ -12,8 +12,9 @@ import ( "strconv" "strings" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) @@ -101,12 +102,12 @@ func (t *BlockTest) InsertPreState(db common.Database) error { statedb := state.New(nil, db) for addrString, acct := range t.preAccounts { // XXX: is is worth it checking for errors here? - addr, _ := hex.DecodeString(addrString) + //addr, _ := hex.DecodeString(addrString) code, _ := hex.DecodeString(strings.TrimPrefix(acct.Code, "0x")) balance, _ := new(big.Int).SetString(acct.Balance, 0) nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64) - obj := statedb.NewStateObject(addr) + obj := statedb.NewStateObject(common.HexToAddress(addrString)) obj.SetCode(code) obj.SetBalance(balance) obj.SetNonce(nonce) @@ -119,7 +120,7 @@ func (t *BlockTest) InsertPreState(db common.Database) error { // sync trie to disk statedb.Sync() - if !bytes.Equal(t.Genesis.Root(), statedb.Root()) { + if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root()) { return errors.New("computed state root does not match genesis block") } return nil @@ -153,23 +154,25 @@ func mustConvertGenesis(testGenesis btHeader) *types.Block { func mustConvertHeader(in btHeader) *types.Header { // hex decode these fields - return &types.Header{ + header := &types.Header{ //SeedHash: mustConvertBytes(in.SeedHash), - MixDigest: mustConvertBytes(in.MixHash), - Bloom: mustConvertBytes(in.Bloom), - ReceiptHash: mustConvertBytes(in.ReceiptTrie), - TxHash: mustConvertBytes(in.TransactionsTrie), - Root: mustConvertBytes(in.StateRoot), - Coinbase: mustConvertBytes(in.Coinbase), - UncleHash: mustConvertBytes(in.UncleHash), - ParentHash: mustConvertBytes(in.ParentHash), - Nonce: mustConvertBytes(in.Nonce), + MixDigest: mustConvertHash(in.MixHash), + Bloom: mustConvertBloom(in.Bloom), + ReceiptHash: mustConvertHash(in.ReceiptTrie), + TxHash: mustConvertHash(in.TransactionsTrie), + Root: mustConvertHash(in.StateRoot), + Coinbase: mustConvertAddress(in.Coinbase), + UncleHash: mustConvertHash(in.UncleHash), + ParentHash: mustConvertHash(in.ParentHash), Extra: string(mustConvertBytes(in.ExtraData)), GasUsed: mustConvertBigInt10(in.GasUsed), GasLimit: mustConvertBigInt10(in.GasLimit), Difficulty: mustConvertBigInt10(in.Difficulty), Time: mustConvertUint(in.Timestamp), } + // XXX cheats? :-) + header.SetNonce(common.BytesToHash(mustConvertBytes(in.Nonce)).Big().Uint64()) + return header } func mustConvertBlocks(testBlocks []btBlock) []*types.Block { @@ -193,6 +196,30 @@ func mustConvertBytes(in string) []byte { return out } +func mustConvertHash(in string) common.Hash { + out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + panic(fmt.Errorf("invalid hex: %q", in)) + } + return common.BytesToHash(out) +} + +func mustConvertAddress(in string) common.Address { + out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + panic(fmt.Errorf("invalid hex: %q", in)) + } + return common.BytesToAddress(out) +} + +func mustConvertBloom(in string) core.Bloom { + out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + panic(fmt.Errorf("invalid hex: %q", in)) + } + return core.BytesToBloom(out) +} + func mustConvertBigInt10(in string) *big.Int { out, ok := new(big.Int).SetString(in, 10) if !ok { diff --git a/vm/environment.go b/vm/environment.go index a53411b23..9de2fd80a 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -3,9 +3,11 @@ package vm import ( "errors" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) @@ -54,7 +56,7 @@ func Transfer(from, to Account, amount *big.Int) error { type Log struct { address common.Address - topics [][]byte + topics []common.Hash data []byte log uint64 } @@ -63,7 +65,7 @@ func (self *Log) Address() common.Address { return self.address } -func (self *Log) Topics() [][]byte { +func (self *Log) Topics() []common.Hash { return self.topics } @@ -75,9 +77,15 @@ func (self *Log) Number() uint64 { return self.log } +func (self *Log) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.address, self.topics, self.data}) +} + +/* func (self *Log) RlpData() interface{} { return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data} } +*/ func (self *Log) String() string { return fmt.Sprintf("[A=%x T=%x D=%x]", self.address, self.topics, self.data) diff --git a/vm/vm.go b/vm/vm.go index 4ef888e36..796a55ad3 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -560,10 +560,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => [%d]", n) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) - topics := make([][]byte, n) + topics := make([]common.Hash, n) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < n; i++ { - topics[i] = common.LeftPadBytes(stack.pop().Bytes(), 32) + topics[i] = common.BigToHash(stack.pop()) //common.LeftPadBytes(stack.pop().Bytes(), 32) } data := mem.Get(mStart.Int64(), mSize.Int64()) From 94505146a21cc0aee16d79aebc17c8fcb1f91324 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 23:17:28 +0100 Subject: [PATCH 14/78] updated vm env --- core/state_transition.go | 6 +++--- core/vm_env.go | 33 +++++++++++++++++---------------- pow/block.go | 5 +++-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 279abee62..575bdf026 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -4,8 +4,8 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -45,8 +45,8 @@ type StateTransition struct { } type Message interface { - From() []byte - To() []byte + From() common.Address + To() common.Address GasPrice() *big.Int Gas() *big.Int diff --git a/core/vm_env.go b/core/vm_env.go index c7491bcdc..7a921d7e3 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -3,6 +3,7 @@ package core import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" @@ -27,18 +28,18 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types } } -func (self *VMEnv) Origin() []byte { return self.msg.From() } -func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } -func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } -func (self *VMEnv) Time() int64 { return self.block.Time() } -func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } -func (self *VMEnv) Value() *big.Int { return self.msg.Value() } -func (self *VMEnv) State() *state.StateDB { return self.state } -func (self *VMEnv) Depth() int { return self.depth } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) VmType() vm.Type { return self.typ } -func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } +func (self *VMEnv) Origin() common.Address { return self.msg.From() } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } +func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } +func (self *VMEnv) Time() int64 { return self.block.Time() } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } +func (self *VMEnv) Value() *big.Int { return self.msg.Value() } +func (self *VMEnv) State() *state.StateDB { return self.state } +func (self *VMEnv) Depth() int { return self.depth } +func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) VmType() vm.Type { return self.typ } +func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } func (self *VMEnv) GetHash(n uint64) []byte { if block := self.chain.GetBlockByNumber(n); block != nil { return block.Hash() @@ -57,16 +58,16 @@ func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution return NewExecution(self, addr, data, gas, price, value) } -func (self *VMEnv) Call(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { +func (self *VMEnv) Call(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { exe := self.vm(addr, data, gas, price, value) return exe.Call(addr, me) } -func (self *VMEnv) CallCode(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { +func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { exe := self.vm(me.Address(), data, gas, price, value) return exe.Call(addr, me) } -func (self *VMEnv) Create(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { - exe := self.vm(addr, data, gas, price, value) +func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { + exe := self.vm(common.Address{}, data, gas, price, value) return exe.Create(me) } diff --git a/pow/block.go b/pow/block.go index 136e4bf8d..9ae25bd4d 100644 --- a/pow/block.go +++ b/pow/block.go @@ -3,14 +3,15 @@ package pow import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) type Block interface { Difficulty() *big.Int - HashNoNonce() []byte + HashNoNonce() common.Hash Nonce() uint64 - MixDigest() []byte + MixDigest() common.Hash NumberU64() uint64 } From 8ce6a3647821706cf5e9bb1a9dc13f23c84f6585 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Mar 2015 23:48:18 +0100 Subject: [PATCH 15/78] converted chain manager --- core/block_processor.go | 38 ++++++++++++++++---------------- core/chain_makers.go | 10 ++++----- core/chain_manager.go | 48 +++++++++++++++++++++++------------------ core/error.go | 6 ++++-- core/types/receipt.go | 2 +- state/state_object.go | 6 +++--- state/statedb.go | 10 ++++----- 7 files changed, 63 insertions(+), 57 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index f67d6d006..fd4009037 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -1,14 +1,13 @@ package core import ( - "bytes" "fmt" "math/big" "sync" "time" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" @@ -90,7 +89,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated statedb.Update(nil) cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas)) - receipt := types.NewReceipt(statedb.Root(), cumulative) + receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative) receipt.SetLogs(statedb.Logs()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) chainlogger.Debugln(receipt) @@ -190,7 +189,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. rbloom := types.CreateBloom(receipts) - if bytes.Compare(rbloom, header.Bloom) != 0 { + if rbloom != header.Bloom { err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return } @@ -198,14 +197,14 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // The transactions Trie's root (R = (Tr [[H1, T1], [H2, T2], ... [Hn, Tn]])) // can be used by light clients to make sure they've received the correct Txs txSha := types.DeriveSha(block.Transactions()) - if bytes.Compare(txSha, header.TxHash) != 0 { + if txSha != header.TxHash { err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha) return } // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) receiptSha := types.DeriveSha(receipts) - if bytes.Compare(receiptSha, header.ReceiptHash) != 0 { + if receiptSha != header.ReceiptHash { err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha) return } @@ -218,7 +217,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // Commit state objects/accounts to a temporary trie (does not save) // used to calculate the state root. state.Update(common.Big0) - if !bytes.Equal(header.Root, state.Root()) { + if header.Root != state.Root() { err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root()) return } @@ -234,7 +233,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big putTx(sm.extraDb, tx) } - chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash()[0:4]) + chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash().Bytes()[0:4]) return td, nil } @@ -284,35 +283,34 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren ancestors := set.New() uncles := set.New() - ancestorHeaders := make(map[string]*types.Header) + ancestorHeaders := make(map[common.Hash]*types.Header) for _, ancestor := range sm.bc.GetAncestors(block, 7) { - hash := string(ancestor.Hash()) - ancestorHeaders[hash] = ancestor.Header() - ancestors.Add(hash) + ancestorHeaders[ancestor.Hash()] = ancestor.Header() + ancestors.Add(ancestor.Hash()) // Include ancestors uncles in the uncle set. Uncles must be unique. for _, uncle := range ancestor.Uncles() { - uncles.Add(string(uncle.Hash())) + uncles.Add(uncle.Hash()) } } - uncles.Add(string(block.Hash())) + uncles.Add(block.Hash()) for _, uncle := range block.Uncles() { - if uncles.Has(string(uncle.Hash())) { + if uncles.Has(uncle.Hash()) { // Error not unique return UncleError("Uncle not unique") } - uncles.Add(string(uncle.Hash())) + uncles.Add(uncle.Hash()) - if ancestors.Has(string(uncle.Hash())) { + if ancestors.Has(uncle.Hash()) { return UncleError("Uncle is ancestor") } - if !ancestors.Has(string(uncle.ParentHash)) { + if !ancestors.Has(uncle.ParentHash) { return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } - if err := sm.ValidateHeader(uncle, ancestorHeaders[string(uncle.ParentHash)]); err != nil { + if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash]); err != nil { return ValidationError(fmt.Sprintf("%v", err)) } @@ -358,5 +356,5 @@ func putTx(db common.Database, tx *types.Transaction) { statelogger.Infoln("Failed encoding tx", err) return } - db.Put(tx.Hash(), rlpEnc) + db.Put(tx.Hash().Bytes(), rlpEnc) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 59c297dbe..857af960c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -4,8 +4,8 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/state" @@ -29,7 +29,7 @@ var ( // Utility functions for making chains on the fly // Exposed for sake of testing from other packages (eg. go-ethash) -func NewBlockFromParent(addr []byte, parent *types.Block) *types.Block { +func NewBlockFromParent(addr common.Address, parent *types.Block) *types.Block { return newBlockFromParent(addr, parent) } @@ -54,7 +54,7 @@ func NewCanonical(n int, db common.Database) (*BlockProcessor, error) { } // block time is fixed at 10 seconds -func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { +func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block { block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, "") block.SetUncles(nil) block.SetTransactions(nil) @@ -74,8 +74,8 @@ func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { // Actually make a block by simulating what miner would do // we seed chains by the first byte of the coinbase func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Database, seed int) *types.Block { - addr := common.LeftPadBytes([]byte{byte(i)}, 20) - addr[0] = byte(seed) + var addr common.Address + addr[0], addr[19] = byte(seed), byte(i) block := newBlockFromParent(addr, parent) state := state.New(block.Root(), db) cbase := state.GetOrNewStateObject(addr) diff --git a/core/chain_manager.go b/core/chain_manager.go index ff91b0427..5316a3423 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -6,8 +6,8 @@ import ( "math/big" "sync" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/rlp" @@ -86,7 +86,7 @@ type ChainManager struct { tsmu sync.RWMutex td *big.Int currentBlock *types.Block - lastBlockHash []byte + lastBlockHash common.Hash transState *state.StateDB txState *state.ManagedState @@ -112,7 +112,7 @@ func (self *ChainManager) Td() *big.Int { return self.td } -func (self *ChainManager) LastBlockHash() []byte { +func (self *ChainManager) LastBlockHash() common.Hash { self.mu.RLock() defer self.mu.RUnlock() @@ -126,7 +126,7 @@ func (self *ChainManager) CurrentBlock() *types.Block { return self.currentBlock } -func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { +func (self *ChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { self.mu.RLock() defer self.mu.RUnlock() @@ -168,7 +168,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) { func (bc *ChainManager) setLastBlock() { data, _ := bc.blockDb.Get([]byte("LastBlock")) if len(data) != 0 { - block := bc.GetBlock(data) + block := bc.GetBlock(common.BytesToHash(data)) bc.currentBlock = block bc.lastBlockHash = block.Hash() @@ -182,12 +182,14 @@ func (bc *ChainManager) setLastBlock() { } // Block creation & chain handling -func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { +func (bc *ChainManager) NewBlock(coinbase common.Address) *types.Block { bc.mu.RLock() defer bc.mu.RUnlock() - var root []byte - parentHash := ZeroHash256 + var ( + root common.Hash + parentHash common.Hash + ) if bc.currentBlock != nil { root = bc.currentBlock.Header().Root @@ -234,7 +236,7 @@ func (bc *ChainManager) Reset() { } func (bc *ChainManager) removeBlock(block *types.Block) { - bc.blockDb.Delete(append(blockHashPre, block.Hash()...)) + bc.blockDb.Delete(append(blockHashPre, block.Hash().Bytes()...)) } func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { @@ -268,18 +270,18 @@ func (self *ChainManager) Export() []byte { func (bc *ChainManager) insert(block *types.Block) { //encodedBlock := common.Encode(block) - bc.blockDb.Put([]byte("LastBlock"), block.Hash()) + bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) bc.currentBlock = block bc.lastBlockHash = block.Hash() key := append(blockNumPre, block.Number().Bytes()...) - bc.blockDb.Put(key, bc.lastBlockHash) + bc.blockDb.Put(key, bc.lastBlockHash.Bytes()) } func (bc *ChainManager) write(block *types.Block) { encodedBlock := common.Encode(block.RlpDataForStorage()) - key := append(blockHashPre, block.Hash()...) + key := append(blockHashPre, block.Hash().Bytes()...) bc.blockDb.Put(key, encodedBlock) } @@ -289,12 +291,12 @@ func (bc *ChainManager) Genesis() *types.Block { } // Block fetching methods -func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := bc.blockDb.Get(append(blockHashPre, hash...)) +func (bc *ChainManager) HasBlock(hash common.Hash) bool { + data, _ := bc.blockDb.Get(append(blockHashPre, hash[:]...)) return len(data) != 0 } -func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) { +func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) (chain []common.Hash) { block := self.GetBlock(hash) if block == nil { return @@ -317,8 +319,8 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain return } -func (self *ChainManager) GetBlock(hash []byte) *types.Block { - data, _ := self.blockDb.Get(append(blockHashPre, hash...)) +func (self *ChainManager) GetBlock(hash common.Hash) *types.Block { + data, _ := self.blockDb.Get(append(blockHashPre, hash[:]...)) if len(data) == 0 { return nil } @@ -340,7 +342,7 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { return nil } - return self.GetBlock(key) + return self.GetBlock(common.BytesToHash(key)) } func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) { @@ -418,7 +420,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } h := block.Header() - chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash()[:4]) + chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()[:4]) chainlogger.Infoln(err) chainlogger.Debugln(block) return err @@ -435,7 +437,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { // At this point it's possible that a different chain (fork) becomes the new canonical chain. if td.Cmp(self.td) > 0 { if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, common.Big1)) < 0 { - chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td) + chash := cblock.Hash() + hash := block.Hash() + chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], td, cblock.Header().Number, chash[:4], self.td) queue[i] = ChainSplitEvent{block} queueEvent.splitCount++ @@ -507,7 +511,9 @@ out: } } +/* // Satisfy state query interface -func (self *ChainManager) GetAccount(addr []byte) *state.StateObject { +func (self *ChainManager) GetAccount(addr common.Hash) *state.StateObject { return self.State().GetAccount(addr) } +*/ diff --git a/core/error.go b/core/error.go index 69e320eb0..f6ac26cff 100644 --- a/core/error.go +++ b/core/error.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "math/big" + + "github.com/ethereum/go-ethereum/common" ) var ( @@ -21,7 +23,7 @@ func (err *ParentErr) Error() string { return err.Message } -func ParentError(hash []byte) error { +func ParentError(hash common.Hash) error { return &ParentErr{Message: fmt.Sprintf("Block's parent unknown %x", hash)} } @@ -136,7 +138,7 @@ func IsTDError(e error) bool { type KnownBlockError struct { number *big.Int - hash []byte + hash common.Hash } func (self *KnownBlockError) Error() string { diff --git a/core/types/receipt.go b/core/types/receipt.go index d0cb41e25..f88d42b29 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -14,7 +14,7 @@ import ( type Receipt struct { PostState []byte CumulativeGasUsed *big.Int - Bloom []byte + Bloom Bloom logs state.Logs } diff --git a/state/state_object.go b/state/state_object.go index 853703350..a7c20722c 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -82,7 +82,7 @@ func NewStateObject(address common.Address, db common.Database) *StateObject { //address := common.ToAddress(addr) object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int), dirty: true} - object.State = New(nil, db) //New(trie.New(common.Config.Db, "")) + object.State = New(common.Hash{}, db) //New(trie.New(common.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) object.prepaid = new(big.Int) @@ -109,7 +109,7 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db common.Data object.nonce = extobject.Nonce object.balance = extobject.Balance object.codeHash = extobject.CodeHash - object.State = New(extobject.Root[:], db) + object.State = New(extobject.Root, db) object.storage = make(map[string]*common.Value) object.gasPool = new(big.Int) object.prepaid = new(big.Int) @@ -339,7 +339,7 @@ func (c *StateObject) RlpDecode(data []byte) { decoder := common.NewValueFromBytes(data) c.nonce = decoder.Get(0).Uint() c.balance = decoder.Get(1).BigInt() - c.State = New(decoder.Get(2).Bytes(), c.db) //New(trie.New(common.Config.Db, decoder.Get(2).Interface())) + c.State = New(common.BytesToHash(decoder.Get(2).Bytes()), c.db) //New(trie.New(common.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*common.Value) c.gasPool = new(big.Int) diff --git a/state/statedb.go b/state/statedb.go index 85fabac78..ea5aad525 100644 --- a/state/statedb.go +++ b/state/statedb.go @@ -28,8 +28,8 @@ type StateDB struct { } // Create a new state from a given trie -func New(root []byte, db common.Database) *StateDB { - trie := trie.NewSecure(common.CopyBytes(root), db) +func New(root common.Hash, db common.Database) *StateDB { + trie := trie.NewSecure(root[:], db) return &StateDB{db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: make(map[string]*big.Int)} } @@ -222,7 +222,7 @@ func (s *StateDB) Cmp(other *StateDB) bool { } func (self *StateDB) Copy() *StateDB { - state := New(nil, self.db) + state := New(common.Hash{}, self.db) state.trie = self.trie.Copy() for k, stateObject := range self.stateObjects { state.stateObjects[k] = stateObject.Copy() @@ -247,8 +247,8 @@ func (self *StateDB) Set(state *StateDB) { self.logs = state.logs } -func (s *StateDB) Root() []byte { - return s.trie.Root() +func (s *StateDB) Root() common.Hash { + return common.BytesToHash(s.trie.Root()) } func (s *StateDB) Trie() *trie.SecureTrie { From ad78db4d62d392e9462ac4c1f8ac3d9718fdd0fc Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 01:32:35 +0100 Subject: [PATCH 16/78] crypto: fix Sha3Hash and add a test for it --- crypto/crypto.go | 2 +- crypto/crypto_test.go | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index 1f8dfcf32..ec2b41042 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -42,7 +42,7 @@ func Sha3Hash(data ...[]byte) (h common.Hash) { for _, b := range data { d.Write(b) } - d.Sum(h[:]) + d.Sum(h[:0]) return h } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 754287641..63a9c3f5e 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) // These tests are sanity checks. @@ -21,6 +21,12 @@ func TestSha3(t *testing.T) { checkhash(t, "Sha3-256", func(in []byte) []byte { return Sha3(in) }, msg, exp) } +func TestSha3Hash(t *testing.T) { + msg := []byte("abc") + exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") + checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Sha3Hash(in); return h[:] }, msg, exp) +} + func TestSha256(t *testing.T) { msg := []byte("abc") exp, _ := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") From d5de6489d7275374a3bb269b07780d6c13b6c3b7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 01:34:18 +0100 Subject: [PATCH 17/78] core/types: fix Transaction.Hash and add support for encoding with package rlp --- core/types/transaction.go | 25 +++++++++++---- core/types/transaction_test.go | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index d55c5d5ae..7f1447ef8 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -3,6 +3,7 @@ package types import ( "bytes" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" @@ -27,12 +28,12 @@ type Transaction struct { R, S []byte } -func NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction { - return NewTransactionMessage(common.Address{}, Amount, gasAmount, price, data) +func NewContractCreationTx(amount, gasAmount, price *big.Int, data []byte) *Transaction { + return NewTransactionMessage(common.Address{}, amount, gasAmount, price, data) } -func NewTransactionMessage(to common.Address, Amount, gasAmount, price *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data} +func NewTransactionMessage(to common.Address, amount, gasAmount, price *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: to, Amount: amount, Price: price, GasLimit: gasAmount, Payload: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -44,7 +45,7 @@ func NewTransactionFromBytes(data []byte) *Transaction { func (tx *Transaction) Hash() (a common.Hash) { h := sha3.NewKeccak256() rlp.Encode(h, []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}) - h.Sum(a[:]) + h.Sum(a[:0]) return a } @@ -84,7 +85,6 @@ func (tx *Transaction) Curve() (v byte, r []byte, s []byte) { v = byte(tx.V) r = common.LeftPadBytes(tx.R, 32) s = common.LeftPadBytes(tx.S, 32) - return } @@ -124,6 +124,19 @@ func (tx *Transaction) SetSignatureValues(sig []byte) error { return nil } +func (tx Transaction) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{ + tx.AccountNonce, + tx.Price, tx.GasLimit, + tx.Recipient, + tx.Amount, + tx.Payload, + tx.V, + tx.R, + tx.S, + }) +} + // TODO: remove func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index ab1254f4c..1af59436e 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -1 +1,57 @@ package types + +import ( + "bytes" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +// The values in those tests are from the Transaction Tests +// at github.com/ethereum/tests. + +var ( + emptyTx = NewTransactionMessage( + common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), + big.NewInt(0), big.NewInt(0), big.NewInt(0), + nil, + ) + + rightvrsTx = &Transaction{ + Recipient: common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), + AccountNonce: 3, + Price: big.NewInt(1), + GasLimit: big.NewInt(2000), + Amount: big.NewInt(10), + Payload: common.FromHex("5544"), + V: 28, + R: common.FromHex("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a"), + S: common.FromHex("8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"), + } +) + +func TestTransactionHash(t *testing.T) { + // "EmptyTransaction" + if emptyTx.Hash() != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") { + t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash()) + } + + // "RightVRSTest" + if rightvrsTx.Hash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") { + t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash()) + } +} + +func TestTransactionEncode(t *testing.T) { + // "RightVRSTest" + txb, err := rlp.EncodeToBytes(rightvrsTx) + if err != nil { + t.Fatalf("encode error: %v", err) + } + should := common.FromHex("f86103018207d094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a8255441ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3") + if !bytes.Equal(txb, should) { + t.Errorf("encoded RLP mismatch, got %x", txb) + } +} From 515d9432fcef8c574627049d437d6898b56c2829 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Mar 2015 11:19:23 +0100 Subject: [PATCH 18/78] converted vm --- core/execution.go | 27 +++++++++++++-------------- core/filter.go | 24 ++++++++++++------------ core/genesis.go | 7 +++---- core/state_transition.go | 22 +++++++++++++--------- core/types/bloom9.go | 6 +++--- core/types/common.go | 10 +++++++++- core/vm_env.go | 37 +++++++++++++++++++------------------ crypto/crypto.go | 7 +++++-- vm/context.go | 4 ++-- vm/environment.go | 6 +++--- vm/vm.go | 10 ++++++---- 11 files changed, 88 insertions(+), 72 deletions(-) diff --git a/core/execution.go b/core/execution.go index be45eeeb4..4f15fb42a 100644 --- a/core/execution.go +++ b/core/execution.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" @@ -11,26 +12,23 @@ import ( type Execution struct { env vm.Environment - address, input []byte + address *common.Address + input []byte Gas, price, value *big.Int } -func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution { +func NewExecution(env vm.Environment, address *common.Address, input []byte, gas, gasPrice, value *big.Int) *Execution { return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value} } -func (self *Execution) Addr() []byte { - return self.address -} - -func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) { +func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]byte, error) { // Retrieve the executing code code := self.env.State().GetCode(codeAddr) - return self.exec(code, codeAddr, caller) + return self.exec(&codeAddr, code, caller) } -func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret []byte, err error) { +func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.ContextRef) (ret []byte, err error) { env := self.env evm := vm.NewVm(env) if env.Depth() == vm.MaxCallDepth { @@ -40,14 +38,15 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret } vsnapshot := env.State().Copy() - if len(self.address) == 0 { + if self.address == nil { // Generate a new address nonce := env.State().GetNonce(caller.Address()) - self.address = crypto.CreateAddress(caller.Address(), nonce) + addr := crypto.CreateAddress(caller.Address(), nonce) + self.address = &addr env.State().SetNonce(caller.Address(), nonce+1) } - from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address) + from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(*self.address) err = env.Transfer(from, to, self.value) if err != nil { env.State().Set(vsnapshot) @@ -73,8 +72,8 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret } func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) { - ret, err = self.exec(self.input, nil, caller) - account = self.env.State().GetStateObject(self.address) + ret, err = self.exec(nil, self.input, caller) + account = self.env.State().GetStateObject(*self.address) return } diff --git a/core/filter.go b/core/filter.go index d58aa8d7c..e08aac120 100644 --- a/core/filter.go +++ b/core/filter.go @@ -1,9 +1,9 @@ package core import ( - "bytes" "math" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/state" ) @@ -16,8 +16,8 @@ type FilterOptions struct { Earliest int64 Latest int64 - Address [][]byte - Topics [][][]byte + Address []common.Address + Topics [][]common.Hash Skip int Max int @@ -29,9 +29,9 @@ type Filter struct { earliest int64 latest int64 skip int - address [][]byte + address []common.Address max int - topics [][][]byte + topics [][]common.Hash BlockCallback func(*types.Block) PendingCallback func(*types.Block) @@ -67,11 +67,11 @@ func (self *Filter) SetLatestBlock(latest int64) { self.latest = latest } -func (self *Filter) SetAddress(addr [][]byte) { +func (self *Filter) SetAddress(addr []common.Address) { self.address = addr } -func (self *Filter) SetTopics(topics [][][]byte) { +func (self *Filter) SetTopics(topics [][]common.Hash) { self.topics = topics } @@ -131,9 +131,9 @@ func (self *Filter) Find() state.Logs { return logs[skip:] } -func includes(addresses [][]byte, a []byte) bool { +func includes(addresses []common.Address, a common.Address) bool { for _, addr := range addresses { - if !bytes.Equal(addr, a) { + if addr != a { return false } } @@ -151,13 +151,13 @@ Logs: continue } - logTopics := make([][]byte, len(self.topics)) + logTopics := make([]common.Hash, len(self.topics)) copy(logTopics, log.Topics()) for i, topics := range self.topics { for _, topic := range topics { var match bool - if bytes.Equal(log.Topics()[i], topic) { + if log.Topics()[i] == topic { match = true } if !match { @@ -176,7 +176,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool { if len(self.address) > 0 { var included bool for _, addr := range self.address { - if types.BloomLookup(block.Bloom(), addr) { + if types.BloomLookup(block.Bloom(), addr.Hash()) { included = true break } diff --git a/core/genesis.go b/core/genesis.go index bfd51f196..70845b502 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -6,9 +6,9 @@ import ( "math/big" "os" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/state" ) @@ -26,12 +26,11 @@ var GenesisDiff = big.NewInt(131072) var GenesisGasLimit = big.NewInt(3141592) func GenesisBlock(db common.Database) *types.Block { - genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, GenesisDiff, 42, "") + genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, GenesisDiff, 42, "") genesis.Header().Number = common.Big0 genesis.Header().GasLimit = GenesisGasLimit genesis.Header().GasUsed = common.Big0 genesis.Header().Time = 0 - genesis.Header().MixDigest = make([]byte, 32) genesis.Td = common.Big0 @@ -49,7 +48,7 @@ func GenesisBlock(db common.Database) *types.Block { statedb := state.New(genesis.Root(), db) for addr, account := range accounts { codedAddr := common.Hex2Bytes(addr) - accountState := statedb.GetAccount(codedAddr) + accountState := statedb.GetAccount(common.BytesToAddress(codedAddr)) accountState.SetBalance(common.Big(account.Balance)) statedb.UpdateStateObject(accountState) } diff --git a/core/state_transition.go b/core/state_transition.go index 575bdf026..ce9835751 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -31,7 +31,7 @@ var () * 6) Derive new state root */ type StateTransition struct { - coinbase []byte + coinbase common.Address msg Message gas, gasPrice *big.Int initialGas *big.Int @@ -119,7 +119,7 @@ func (self *StateTransition) BuyGas() error { sender := self.From() if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 { - return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance()) + return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], MessageGasValue(self.msg), sender.Balance()) } coinbase := self.Coinbase() @@ -195,8 +195,9 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er vmenv := self.env var ref vm.ContextRef if MessageCreatesContract(msg) { - contract := makeContract(msg, self.state) - ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) + //contract := makeContract(msg, self.state) + //addr := contract.Address() + ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value) if err == nil { dataGas := big.NewInt(int64(len(ret))) dataGas.Mul(dataGas, vm.GasCreateByte) @@ -230,7 +231,7 @@ func (self *StateTransition) refundGas() { for addr, ref := range self.state.Refunds() { refund := common.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) - self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) + self.state.AddBalance(common.StringToAddress(addr), refund.Mul(refund, self.msg.GasPrice())) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) @@ -242,10 +243,13 @@ func (self *StateTransition) gasUsed() *big.Int { // Converts an message in to a state object func makeContract(msg Message, state *state.StateDB) *state.StateObject { - addr := AddressFromMessage(msg) + /* + addr := AddressFromMessage(msg) - contract := state.GetOrNewStateObject(addr) - contract.SetInitCode(msg.Data()) + contract := state.GetOrNewStateObject(addr) + contract.SetInitCode(msg.Data()) - return contract + return contract + */ + return nil } diff --git a/core/types/bloom9.go b/core/types/bloom9.go index b3cab86a0..55bfe2756 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -47,9 +47,9 @@ func bloom9(b []byte) *big.Int { return r } -func BloomLookup(bin, topic []byte) bool { - bloom := common.BigD(bin) - cmp := bloom9(crypto.Sha3(topic)) +func BloomLookup(bin Bloom, topic common.Hash) bool { + bloom := bin.Big() + cmp := bloom9(crypto.Sha3(topic[:])) return bloom.And(bloom, cmp).Cmp(cmp) == 0 } diff --git a/core/types/common.go b/core/types/common.go index dd5dc00c8..6c5ac06b1 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -1,6 +1,10 @@ package types -import "math/big" +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) type BlockProcessor interface { Process(*Block) (*big.Int, error) @@ -24,3 +28,7 @@ func (b *Bloom) SetBytes(d []byte) { b[i] = b[i] } } + +func (b Bloom) Big() *big.Int { + return common.Bytes2Big(b[:]) +} diff --git a/core/vm_env.go b/core/vm_env.go index 7a921d7e3..fb4253f5b 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -28,24 +28,24 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types } } -func (self *VMEnv) Origin() common.Address { return self.msg.From() } -func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } -func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } -func (self *VMEnv) Time() int64 { return self.block.Time() } -func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } -func (self *VMEnv) Value() *big.Int { return self.msg.Value() } -func (self *VMEnv) State() *state.StateDB { return self.state } -func (self *VMEnv) Depth() int { return self.depth } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) VmType() vm.Type { return self.typ } -func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } -func (self *VMEnv) GetHash(n uint64) []byte { +func (self *VMEnv) Origin() common.Address { return self.msg.From() } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } +func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() } +func (self *VMEnv) Time() int64 { return self.block.Time() } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } +func (self *VMEnv) Value() *big.Int { return self.msg.Value() } +func (self *VMEnv) State() *state.StateDB { return self.state } +func (self *VMEnv) Depth() int { return self.depth } +func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) VmType() vm.Type { return self.typ } +func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } +func (self *VMEnv) GetHash(n uint64) common.Hash { if block := self.chain.GetBlockByNumber(n); block != nil { return block.Hash() } - return nil + return common.Hash{} } func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) @@ -54,20 +54,21 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } -func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution { +func (self *VMEnv) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *Execution { return NewExecution(self, addr, data, gas, price, value) } func (self *VMEnv) Call(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - exe := self.vm(addr, data, gas, price, value) + exe := self.vm(&addr, data, gas, price, value) return exe.Call(addr, me) } func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - exe := self.vm(me.Address(), data, gas, price, value) + maddr := me.Address() + exe := self.vm(&maddr, data, gas, price, value) return exe.Call(addr, me) } func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { - exe := self.vm(common.Address{}, data, gas, price, value) + exe := self.vm(nil, data, gas, price, value) return exe.Create(me) } diff --git a/crypto/crypto.go b/crypto/crypto.go index 1f8dfcf32..e9582ac77 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/ripemd160" ) @@ -47,8 +48,10 @@ func Sha3Hash(data ...[]byte) (h common.Hash) { } // Creates an ethereum address given the bytes and the nonce -func CreateAddress(b []byte, nonce uint64) []byte { - return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:] +func CreateAddress(b common.Address, nonce uint64) common.Address { + data, _ := rlp.EncodeToBytes([]interface{}{b, nonce}) + return common.BytesToAddress(Sha3(data)[12:]) + //return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:] } func Sha256(data []byte) []byte { diff --git a/vm/context.go b/vm/context.go index 93a0102d4..c846aad89 100644 --- a/vm/context.go +++ b/vm/context.go @@ -18,7 +18,7 @@ type Context struct { self ContextRef Code []byte - CodeAddr common.Address + CodeAddr *common.Address value, Gas, UsedGas, Price *big.Int @@ -108,7 +108,7 @@ func (self *Context) SetCode(code []byte) { self.Code = code } -func (self *Context) SetCallCode(addr common.Address, code []byte) { +func (self *Context) SetCallCode(addr *common.Address, code []byte) { self.Code = code self.CodeAddr = addr } diff --git a/vm/environment.go b/vm/environment.go index 9de2fd80a..6976d6749 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -16,8 +16,8 @@ type Environment interface { Origin() common.Address BlockNumber() *big.Int - GetHash(n uint64) []byte - Coinbase() []byte + GetHash(n uint64) common.Hash + Coinbase() common.Address Time() int64 Difficulty() *big.Int GasLimit() *big.Int @@ -38,7 +38,7 @@ type Account interface { SubBalance(amount *big.Int) AddBalance(amount *big.Int) Balance() *big.Int - Address() []byte + Address() common.Address } // generic transfer method diff --git a/vm/vm.go b/vm/vm.go index 796a55ad3..706a3e108 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -58,8 +58,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { }() } - if p := Precompiled[context.CodeAddr.Str()]; p != nil { - return self.RunPrecompiled(p, callData, context) + if context.CodeAddr != nil { + if p := Precompiled[context.CodeAddr.Str()]; p != nil { + return self.RunPrecompiled(p, callData, context) + } } var ( @@ -500,7 +502,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257) if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 { - stack.push(common.BigD(self.env.GetHash(num.Uint64()))) + stack.push(self.env.GetHash(num.Uint64()).Big()) } else { stack.push(common.Big0) } @@ -509,7 +511,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case COINBASE: coinbase := self.env.Coinbase() - stack.push(common.BigD(coinbase)) + stack.push(coinbase.Big()) self.Printf(" => 0x%x", coinbase) case TIMESTAMP: From e91ab84dbe4ef87b2f182b88e5b252b5d414df28 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 11:58:31 +0100 Subject: [PATCH 19/78] core/types: don't use Address zero value for invalid addresses --- core/types/transaction.go | 59 ++++++++++++++++++++-------------- core/types/transaction_test.go | 5 +-- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 7f1447ef8..24035a3ae 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "errors" "fmt" "io" "math/big" @@ -21,19 +22,19 @@ type Transaction struct { AccountNonce uint64 Price *big.Int GasLimit *big.Int - Recipient common.Address + Recipient *common.Address // nil means contract creation Amount *big.Int Payload []byte V byte R, S []byte } -func NewContractCreationTx(amount, gasAmount, price *big.Int, data []byte) *Transaction { - return NewTransactionMessage(common.Address{}, amount, gasAmount, price, data) +func NewContractCreationTx(amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: nil, Amount: amount, GasLimit: gasLimit, Price: gasPrice, Payload: data} } -func NewTransactionMessage(to common.Address, amount, gasAmount, price *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Amount: amount, Price: price, GasLimit: gasAmount, Payload: data} +func NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: &to, Amount: amount, GasLimit: gasAmount, Price: gasPrice, Payload: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -73,12 +74,21 @@ func (self *Transaction) SetNonce(AccountNonce uint64) { self.AccountNonce = AccountNonce } -func (self *Transaction) From() common.Address { - return self.sender() +func (self *Transaction) From() (common.Address, error) { + pubkey := self.PublicKey() + if len(pubkey) == 0 || pubkey[0] != 4 { + return common.Address{}, errors.New("invalid public key") + } + var addr common.Address + copy(addr[:], crypto.Sha3(pubkey[1:])) + return addr, nil } -func (self *Transaction) To() common.Address { - return self.Recipient +// To returns the recipient of the transaction. +// If transaction is a contract creation (with no recipient address) +// To returns nil. +func (tx *Transaction) To() *common.Address { + return tx.Recipient } func (tx *Transaction) Curve() (v byte, r []byte, s []byte) { @@ -105,18 +115,6 @@ func (tx *Transaction) PublicKey() []byte { return pubkey } -func (tx *Transaction) sender() (a common.Address) { - pubkey := tx.PublicKey() - - // Validate the returned key. - // Return nil if public key isn't in full format - if len(pubkey) == 0 || pubkey[0] != 4 { - return a - } - copy(a[:], crypto.Sha3(pubkey[1:])) - return a -} - func (tx *Transaction) SetSignatureValues(sig []byte) error { tx.R = sig[:32] tx.S = sig[32:64] @@ -149,11 +147,22 @@ func (tx *Transaction) RlpEncode() []byte { } func (tx *Transaction) String() string { + var from, to string + if f, err := tx.From(); err != nil { + from = "[invalid sender]" + } else { + from = fmt.Sprintf("%x", f[:]) + } + if t := tx.To(); t == nil { + to = "[contract creation]" + } else { + to = fmt.Sprintf("%x", t[:]) + } return fmt.Sprintf(` TX(%x) Contract: %v - From: %x - To: %x + From: %s + To: %s Nonce: %v GasPrice: %v GasLimit %v @@ -166,8 +175,8 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - tx.From(), - tx.To(), + from, + to, tx.AccountNonce, tx.Price, tx.GasLimit, diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 1af59436e..0b0dfe3ff 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -19,8 +19,9 @@ var ( nil, ) - rightvrsTx = &Transaction{ - Recipient: common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), + rightvrsRecipient = common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b") + rightvrsTx = &Transaction{ + Recipient: &rightvrsRecipient, AccountNonce: 3, Price: big.NewInt(1), GasLimit: big.NewInt(2000), From b95387a0dc0da6198549689e6b03d21a221e813b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 11:59:26 +0100 Subject: [PATCH 20/78] core: convert transaction pool to common.{Address,Hash} --- core/transaction_pool.go | 54 ++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 515cc2040..2efc0511c 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -5,8 +5,8 @@ import ( "fmt" "sync" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" ) @@ -20,9 +20,7 @@ var ( const txPoolQueueSize = 50 type TxPoolHook chan *types.Transaction -type TxMsg struct { - Tx *types.Transaction -} +type TxMsg struct{ Tx *types.Transaction } const ( minGasPrice = 1000000 @@ -44,7 +42,7 @@ type TxPool struct { quit chan bool // The actual pool //pool *list.List - txs map[string]*types.Transaction + txs map[common.Hash]*types.Transaction SecondaryProcessor TxProcessor @@ -55,7 +53,7 @@ type TxPool struct { func NewTxPool(eventMux *event.TypeMux) *TxPool { return &TxPool{ - txs: make(map[string]*types.Transaction), + txs: make(map[common.Hash]*types.Transaction), queueChan: make(chan *types.Transaction, txPoolQueueSize), quit: make(chan bool), eventMux: eventMux, @@ -63,21 +61,16 @@ func NewTxPool(eventMux *event.TypeMux) *TxPool { } func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { - if len(tx.To()) != 0 && len(tx.To()) != 20 { - return fmt.Errorf("Invalid recipient. len = %d", len(tx.To())) + // Validate sender + if _, err := tx.From(); err != nil { + return err } - // Validate curve param v, _, _ := tx.Curve() if v > 28 || v < 27 { return fmt.Errorf("tx.v != (28 || 27) => %v", v) } - - // Validate sender address - senderAddr := tx.From() - if senderAddr == nil || len(senderAddr) != 20 { - return ErrInvalidSender - } + return nil /* XXX this kind of validation needs to happen elsewhere in the gui when sending txs. Other clients should do their own validation. Value transfer could throw error @@ -91,19 +84,16 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From()) } */ - - return nil } func (self *TxPool) addTx(tx *types.Transaction) { - self.txs[string(tx.Hash())] = tx + self.txs[tx.Hash()] = tx } func (self *TxPool) add(tx *types.Transaction) error { - if self.txs[string(tx.Hash())] != nil { + if self.txs[tx.Hash()] != nil { return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4]) } - err := self.ValidateTransaction(tx) if err != nil { return err @@ -111,18 +101,16 @@ func (self *TxPool) add(tx *types.Transaction) error { self.addTx(tx) - var to string - if len(tx.To()) > 0 { - to = common.Bytes2Hex(tx.To()[:4]) + var toname string + if to, valid := tx.To(); valid { + toname = common.Bytes2Hex(to[:4]) } else { - to = "[NEW_CONTRACT]" - } - var from string - if len(tx.From()) > 0 { - from = common.Bytes2Hex(tx.From()[:4]) - } else { - return errors.New(fmt.Sprintf("FROM ADDRESS MUST BE POSITIVE (was %v)", tx.From())) + toname = "[NEW_CONTRACT]" } + // we can ignore the error here because From is + // verified in ValidateTransaction. + f, _ := tx.From() + from := common.Bytes2Hex(f[:4]) txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash()) // Notify the subscribers @@ -140,6 +128,7 @@ func (self *TxPool) Add(tx *types.Transaction) error { defer self.mu.Unlock() return self.add(tx) } + func (self *TxPool) AddTransactions(txs []*types.Transaction) { self.mu.Lock() defer self.mu.Unlock() @@ -186,14 +175,13 @@ func (pool *TxPool) RemoveInvalid(query StateQuery) { func (self *TxPool) RemoveSet(txs types.Transactions) { self.mu.Lock() defer self.mu.Unlock() - for _, tx := range txs { - delete(self.txs, string(tx.Hash())) + delete(self.txs, tx.Hash()) } } func (pool *TxPool) Flush() { - pool.txs = make(map[string]*types.Transaction) + pool.txs = make(map[common.Hash]*types.Transaction) } func (pool *TxPool) Start() { From 27f7aa01639696f4afa4233e0a301afafdd7b950 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 12:00:29 +0100 Subject: [PATCH 21/78] core: adapt Message for new Transaction.From signature --- core/block_processor.go | 3 ++- core/state_transition.go | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index fd4009037..b12f88c47 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -81,7 +81,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb) if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { // If the account is managed, remove the invalid nonce. - self.bc.TxState().RemoveNonce(tx.From(), tx.Nonce()) + from, _ := tx.From() + self.bc.TxState().RemoveNonce(from, tx.Nonce()) return nil, nil, err } diff --git a/core/state_transition.go b/core/state_transition.go index 575bdf026..ef822e86c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -44,9 +44,10 @@ type StateTransition struct { env vm.Environment } +// Message represents a message sent to a contract. type Message interface { - From() common.Address - To() common.Address + From() (common.Address, error) + To() *common.Address GasPrice() *big.Int Gas() *big.Int From 65eee2006d649b2b4f4fef9332d339444bb479b1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 12:01:21 +0100 Subject: [PATCH 22/78] pow/ezp: use common.Hash --- pow/ezp/pow.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go index 7eba95784..bd2927fe8 100644 --- a/pow/ezp/pow.go +++ b/pow/ezp/pow.go @@ -6,8 +6,8 @@ import ( "math/rand" "time" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" ) @@ -83,17 +83,14 @@ func (pow *EasyPow) Verify(block pow.Block) bool { return Verify(block) } -func verify(hash []byte, diff *big.Int, nonce uint64) bool { +func verify(hash common.Hash, diff *big.Int, nonce uint64) bool { sha := sha3.NewKeccak256() - n := make([]byte, 8) binary.PutUvarint(n, nonce) - d := append(hash, n...) - sha.Write(d) - + sha.Write(n) + sha.Write(hash[:]) verification := new(big.Int).Div(common.BigPow(2, 256), diff) res := common.BigD(sha.Sum(nil)) - return res.Cmp(verification) <= 0 } From 17c5ba2b6bfaaeab423f96523b9da13a8fb3febd Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 12:16:21 +0100 Subject: [PATCH 23/78] core: actually convert transaction pool --- core/state_transition.go | 19 +++++++++---------- core/transaction_pool.go | 15 +++++++++------ core/vm_env.go | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 29de501b0..72999de7e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -57,13 +56,8 @@ type Message interface { Data() []byte } -func AddressFromMessage(msg Message) []byte { - // Generate a new address - return crypto.Sha3(common.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:] -} - func MessageCreatesContract(msg Message) bool { - return len(msg.To()) == 0 + return msg.To() == nil } func MessageGasValue(msg Message) *big.Int { @@ -93,13 +87,18 @@ func (self *StateTransition) Coinbase() *state.StateObject { return self.state.GetOrNewStateObject(self.coinbase) } func (self *StateTransition) From() *state.StateObject { - return self.state.GetOrNewStateObject(self.msg.From()) + f, _ := self.msg.From() + return self.state.GetOrNewStateObject(f) } func (self *StateTransition) To() *state.StateObject { - if self.msg != nil && MessageCreatesContract(self.msg) { + if self.msg == nil { return nil } - return self.state.GetOrNewStateObject(self.msg.To()) + to := self.msg.To() + if to == nil { + return nil // contract creation + } + return self.state.GetOrNewStateObject(*to) } func (self *StateTransition) UseGas(amount *big.Int) error { diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 2efc0511c..7c50e5e53 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -91,8 +91,9 @@ func (self *TxPool) addTx(tx *types.Transaction) { } func (self *TxPool) add(tx *types.Transaction) error { - if self.txs[tx.Hash()] != nil { - return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4]) + hash := tx.Hash() + if self.txs[hash] != nil { + return fmt.Errorf("Known transaction (%x)", hash[0:4]) } err := self.ValidateTransaction(tx) if err != nil { @@ -102,7 +103,7 @@ func (self *TxPool) add(tx *types.Transaction) error { self.addTx(tx) var toname string - if to, valid := tx.To(); valid { + if to := tx.To(); to != nil { toname = common.Bytes2Hex(to[:4]) } else { toname = "[NEW_CONTRACT]" @@ -111,7 +112,7 @@ func (self *TxPool) add(tx *types.Transaction) error { // verified in ValidateTransaction. f, _ := tx.From() from := common.Bytes2Hex(f[:4]) - txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash()) + txplogger.Debugf("(t) %x => %s (%v) %x\n", from, toname, tx.Value, tx.Hash()) // Notify the subscribers go self.eventMux.Post(TxPreEvent{tx}) @@ -137,7 +138,8 @@ func (self *TxPool) AddTransactions(txs []*types.Transaction) { if err := self.add(tx); err != nil { txplogger.Debugln(err) } else { - txplogger.Debugf("tx %x\n", tx.Hash()[0:4]) + h := tx.Hash() + txplogger.Debugf("tx %x\n", h[:4]) } } } @@ -161,7 +163,8 @@ func (pool *TxPool) RemoveInvalid(query StateQuery) { var removedTxs types.Transactions for _, tx := range pool.txs { - sender := query.GetAccount(tx.From()) + from, _ := tx.From() + sender := query.GetAccount(from[:]) err := pool.ValidateTransaction(tx) if err != nil || sender.Nonce() >= tx.Nonce() { removedTxs = append(removedTxs, tx) diff --git a/core/vm_env.go b/core/vm_env.go index fb4253f5b..1ddbd5e5e 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -28,7 +28,7 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types } } -func (self *VMEnv) Origin() common.Address { return self.msg.From() } +func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() } func (self *VMEnv) Time() int64 { return self.block.Time() } From b0ebccb31e944e7cb7fabbbecf279a5507e513ab Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Mar 2015 12:56:29 +0100 Subject: [PATCH 24/78] fixed to --- tests/helper/vm.go | 90 ++++++++++++++++++++++++--------------------- tests/vm/gh_test.go | 25 ++++++++----- 2 files changed, 65 insertions(+), 50 deletions(-) diff --git a/tests/helper/vm.go b/tests/helper/vm.go index a7fd98696..f59abd23a 100644 --- a/tests/helper/vm.go +++ b/tests/helper/vm.go @@ -4,9 +4,9 @@ import ( "errors" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -18,9 +18,9 @@ type Env struct { initial bool Gas *big.Int - origin []byte - parent []byte - coinbase []byte + origin common.Address + //parent common.Hash + coinbase common.Address number *big.Int time int64 @@ -41,9 +41,9 @@ func NewEnv(state *state.StateDB) *Env { func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env { env := NewEnv(state) - env.origin = common.Hex2Bytes(exeValues["caller"]) - env.parent = common.Hex2Bytes(envValues["previousHash"]) - env.coinbase = common.Hex2Bytes(envValues["currentCoinbase"]) + env.origin = common.HexToAddress(exeValues["caller"]) + //env.parent = common.Hex2Bytes(envValues["previousHash"]) + env.coinbase = common.HexToAddress(envValues["currentCoinbase"]) env.number = common.Big(envValues["currentNumber"]) env.time = common.Big(envValues["currentTimestamp"]).Int64() env.difficulty = common.Big(envValues["currentDifficulty"]) @@ -53,17 +53,18 @@ func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues return env } -func (self *Env) Origin() []byte { return self.origin } -func (self *Env) BlockNumber() *big.Int { return self.number } -func (self *Env) PrevHash() []byte { return self.parent } -func (self *Env) Coinbase() []byte { return self.coinbase } -func (self *Env) Time() int64 { return self.time } -func (self *Env) Difficulty() *big.Int { return self.difficulty } -func (self *Env) State() *state.StateDB { return self.state } -func (self *Env) GasLimit() *big.Int { return self.gasLimit } -func (self *Env) VmType() vm.Type { return vm.StdVmTy } -func (self *Env) GetHash(n uint64) []byte { - return crypto.Sha3([]byte(big.NewInt(int64(n)).String())) +func (self *Env) Origin() common.Address { return self.origin } +func (self *Env) BlockNumber() *big.Int { return self.number } + +//func (self *Env) PrevHash() []byte { return self.parent } +func (self *Env) Coinbase() common.Address { return self.coinbase } +func (self *Env) Time() int64 { return self.time } +func (self *Env) Difficulty() *big.Int { return self.difficulty } +func (self *Env) State() *state.StateDB { return self.state } +func (self *Env) GasLimit() *big.Int { return self.gasLimit } +func (self *Env) VmType() vm.Type { return vm.StdVmTy } +func (self *Env) GetHash(n uint64) common.Hash { + return common.BytesToHash(crypto.Sha3([]byte(big.NewInt(int64(n)).String()))) } func (self *Env) AddLog(log state.Log) { self.logs = append(self.logs, log) @@ -87,37 +88,39 @@ func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } -func (self *Env) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution { +func (self *Env) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *core.Execution { exec := core.NewExecution(self, addr, data, gas, price, value) return exec } -func (self *Env) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { +func (self *Env) Call(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { if self.vmTest && self.depth > 0 { caller.ReturnGas(gas, price) return nil, nil } - exe := self.vm(addr, data, gas, price, value) + exe := self.vm(&addr, data, gas, price, value) ret, err := exe.Call(addr, caller) self.Gas = exe.Gas return ret, err } -func (self *Env) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { +func (self *Env) CallCode(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { if self.vmTest && self.depth > 0 { caller.ReturnGas(gas, price) return nil, nil } - exe := self.vm(caller.Address(), data, gas, price, value) + + caddr := caller.Address() + exe := self.vm(&caddr, data, gas, price, value) return exe.Call(addr, caller) } -func (self *Env) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { - exe := self.vm(addr, data, gas, price, value) +func (self *Env) Create(caller vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { + exe := self.vm(nil, data, gas, price, value) if self.vmTest { caller.ReturnGas(gas, price) @@ -132,8 +135,8 @@ func (self *Env) Create(caller vm.ContextRef, addr, data []byte, gas, price, val func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Logs, *big.Int, error) { var ( - to = FromHex(exec["address"]) - from = FromHex(exec["caller"]) + to = common.HexToAddress(exec["address"]) + from = common.HexToAddress(exec["caller"]) data = FromHex(exec["data"]) gas = common.Big(exec["gas"]) price = common.Big(exec["gasPrice"]) @@ -156,14 +159,18 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Log func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.Logs, *big.Int, error) { var ( keyPair, _ = crypto.NewKeyPairFromSec([]byte(common.Hex2Bytes(tx["secretKey"]))) - to = FromHex(tx["to"]) data = FromHex(tx["data"]) gas = common.Big(tx["gasLimit"]) price = common.Big(tx["gasPrice"]) value = common.Big(tx["value"]) - caddr = FromHex(env["currentCoinbase"]) + caddr = common.HexToAddress(env["currentCoinbase"]) ) + var to *common.Address + if len(tx["to"]) > 2 { + t := common.HexToAddress(tx["to"]) + to = &t + } // Set pre compiled contracts vm.Precompiled = vm.PrecompiledContracts() @@ -171,9 +178,9 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state. coinbase := statedb.GetOrNewStateObject(caddr) coinbase.SetGasPool(common.Big(env["currentGasLimit"])) - message := NewMessage(keyPair.Address(), to, data, value, gas, price) + message := NewMessage(common.BytesToAddress(keyPair.Address()), to, data, value, gas, price) vmenv := NewEnvFromMap(statedb, env, tx) - vmenv.origin = keyPair.Address() + vmenv.origin = common.BytesToAddress(keyPair.Address()) ret, _, err := core.ApplyMessage(vmenv, message, coinbase) if core.IsNonceErr(err) || core.IsInvalidTxErr(err) { statedb.Set(snapshot) @@ -184,20 +191,21 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state. } type Message struct { - from, to []byte + from common.Address + to *common.Address value, gas, price *big.Int data []byte } -func NewMessage(from, to, data []byte, value, gas, price *big.Int) Message { +func NewMessage(from common.Address, to *common.Address, data []byte, value, gas, price *big.Int) Message { return Message{from, to, value, gas, price, data} } -func (self Message) Hash() []byte { return nil } -func (self Message) From() []byte { return self.from } -func (self Message) To() []byte { return self.to } -func (self Message) GasPrice() *big.Int { return self.price } -func (self Message) Gas() *big.Int { return self.gas } -func (self Message) Value() *big.Int { return self.value } -func (self Message) Nonce() uint64 { return 0 } -func (self Message) Data() []byte { return self.data } +func (self Message) Hash() []byte { return nil } +func (self Message) From() (common.Address, error) { return self.from, nil } +func (self Message) To() *common.Address { return self.to } +func (self Message) GasPrice() *big.Int { return self.price } +func (self Message) Gas() *big.Int { return self.gas } +func (self Message) Value() *big.Int { return self.value } +func (self Message) Nonce() uint64 { return 0 } +func (self Message) Data() []byte { return self.data } diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go index 24718de7b..159561c62 100644 --- a/tests/vm/gh_test.go +++ b/tests/vm/gh_test.go @@ -6,11 +6,12 @@ import ( "strconv" "testing" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/tests/helper" + "github.com/ethereum/go-ethereum/vm" ) type Account struct { @@ -39,7 +40,7 @@ func (self Log) Topics() [][]byte { } func StateObjectFromAccount(db common.Database, addr string, account Account) *state.StateObject { - obj := state.NewStateObject(common.Hex2Bytes(addr), db) + obj := state.NewStateObject(common.HexToAddress(addr), db) obj.SetBalance(common.Big(account.Balance)) if common.IsHex(account.Code) { @@ -80,13 +81,18 @@ func RunVmTest(p string, t *testing.T) { helper.CreateFileTests(t, p, &tests) for name, test := range tests { + helper.Logger.SetLogLevel(5) + vm.Debug = true + if name != "TransactionCreateSuicideContract" { + continue + } db, _ := ethdb.NewMemDatabase() - statedb := state.New(nil, db) + statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) for a, v := range account.Storage { - obj.SetState(helper.FromHex(a), common.NewValue(helper.FromHex(v))) + obj.SetState(common.HexToHash(a), common.NewValue(helper.FromHex(v))) } } @@ -134,30 +140,31 @@ func RunVmTest(p string, t *testing.T) { } for addr, account := range test.Post { - obj := statedb.GetStateObject(helper.FromHex(addr)) + obj := statedb.GetStateObject(common.HexToAddress(addr)) if obj == nil { continue } if len(test.Exec) == 0 { if obj.Balance().Cmp(common.Big(account.Balance)) != 0 { - t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) + t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) } } for addr, value := range account.Storage { - v := obj.GetState(helper.FromHex(addr)).Bytes() + v := obj.GetState(common.HexToHash(addr)).Bytes() vexp := helper.FromHex(value) if bytes.Compare(v, vexp) != 0 { - t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) + t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) } } } if !isVmTest { statedb.Sync() - if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { + //if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { + if common.HexToHash(test.PostStateRoot) != statedb.Root() { t.Errorf("%s's : Post state root error. Expected %s, got %x", name, test.PostStateRoot, statedb.Root()) } } From 0fa7859b94ddb0a35a6fbdb2c29139b0baaa2bfa Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Mar 2015 13:24:12 +0100 Subject: [PATCH 25/78] Fixed VM & Tests w/ conversion --- common/types_test.go | 15 +++++++++++++++ core/state_transition.go | 19 +++++++++---------- core/vm_env.go | 4 ++-- tests/helper/vm.go | 4 ++-- tests/vm/gh_test.go | 6 ------ vm/environment.go | 2 +- vm/vm.go | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 common/types_test.go diff --git a/common/types_test.go b/common/types_test.go new file mode 100644 index 000000000..9f303152c --- /dev/null +++ b/common/types_test.go @@ -0,0 +1,15 @@ +package common + +import "testing" + +func TestBytesConversion(t *testing.T) { + bytes := []byte{5} + hash := BytesToHash(bytes) + + var exp Hash + exp[31] = 5 + + if hash != exp { + t.Errorf("expected %x got %x", exp, hash) + } +} diff --git a/core/state_transition.go b/core/state_transition.go index 72999de7e..1509a5258 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -195,9 +196,9 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er vmenv := self.env var ref vm.ContextRef if MessageCreatesContract(msg) { - //contract := makeContract(msg, self.state) - //addr := contract.Address() - ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value) + contract := makeContract(msg, self.state) + addr := contract.Address() + ret, err, ref = vmenv.Create(sender, &addr, self.msg.Data(), self.gas, self.gasPrice, self.value) if err == nil { dataGas := big.NewInt(int64(len(ret))) dataGas.Mul(dataGas, vm.GasCreateByte) @@ -243,13 +244,11 @@ func (self *StateTransition) gasUsed() *big.Int { // Converts an message in to a state object func makeContract(msg Message, state *state.StateDB) *state.StateObject { - /* - addr := AddressFromMessage(msg) + faddr, _ := msg.From() + addr := crypto.CreateAddress(faddr, msg.Nonce()) - contract := state.GetOrNewStateObject(addr) - contract.SetInitCode(msg.Data()) + contract := state.GetOrNewStateObject(addr) + contract.SetInitCode(msg.Data()) - return contract - */ - return nil + return contract } diff --git a/core/vm_env.go b/core/vm_env.go index 1ddbd5e5e..7845d1cd9 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -68,7 +68,7 @@ func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, return exe.Call(addr, me) } -func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { - exe := self.vm(nil, data, gas, price, value) +func (self *VMEnv) Create(me vm.ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { + exe := self.vm(addr, data, gas, price, value) return exe.Create(me) } diff --git a/tests/helper/vm.go b/tests/helper/vm.go index f59abd23a..44c108870 100644 --- a/tests/helper/vm.go +++ b/tests/helper/vm.go @@ -119,8 +119,8 @@ func (self *Env) CallCode(caller vm.ContextRef, addr common.Address, data []byte return exe.Call(addr, caller) } -func (self *Env) Create(caller vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { - exe := self.vm(nil, data, gas, price, value) +func (self *Env) Create(caller vm.ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { + exe := self.vm(addr, data, gas, price, value) if self.vmTest { caller.ReturnGas(gas, price) diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go index 159561c62..f352e862d 100644 --- a/tests/vm/gh_test.go +++ b/tests/vm/gh_test.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/tests/helper" - "github.com/ethereum/go-ethereum/vm" ) type Account struct { @@ -81,11 +80,6 @@ func RunVmTest(p string, t *testing.T) { helper.CreateFileTests(t, p, &tests) for name, test := range tests { - helper.Logger.SetLogLevel(5) - vm.Debug = true - if name != "TransactionCreateSuicideContract" { - continue - } db, _ := ethdb.NewMemDatabase() statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { diff --git a/vm/environment.go b/vm/environment.go index 6976d6749..fdce526ee 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -31,7 +31,7 @@ type Environment interface { Call(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) CallCode(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) - Create(me ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) + Create(me ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) } type Account interface { diff --git a/vm/vm.go b/vm/vm.go index 706a3e108..49e8cca98 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -641,7 +641,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Endl() context.UseGas(context.Gas) - ret, suberr, ref := self.env.Create(context, input, gas, price, value) + ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value) if suberr != nil { stack.push(common.BigFalse) From c21293cd91f5cd95a823065eb2345c840feec1a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Mar 2015 16:05:17 +0100 Subject: [PATCH 26/78] bloom --- core/types/bloom9.go | 7 ++++--- tests/vm/gh_test.go | 25 +++++++++++++++---------- vm/environment.go | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/core/types/bloom9.go b/core/types/bloom9.go index 55bfe2756..59b6c69c3 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -28,7 +28,7 @@ func LogsBloom(logs state.Logs) *big.Int { } for _, b := range data { - bin.Or(bin, common.BigD(bloom9(crypto.Sha3(b[:])).Bytes())) + bin.Or(bin, bloom9(crypto.Sha3(b[:]))) } } @@ -38,9 +38,10 @@ func LogsBloom(logs state.Logs) *big.Int { func bloom9(b []byte) *big.Int { r := new(big.Int) - for i := 0; i < 16; i += 2 { + for i := 0; i < 6; i += 2 { t := big.NewInt(1) - b := uint(b[i+1]) + 1024*(uint(b[i])&1) + //b := uint(b[i+1]) + 512*(uint(b[i])&1) + b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 511 r.Or(r, t.Lsh(t, b)) } diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go index f352e862d..bce34bb5d 100644 --- a/tests/vm/gh_test.go +++ b/tests/vm/gh_test.go @@ -2,11 +2,13 @@ package vm import ( "bytes" + "fmt" "math/big" "strconv" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" @@ -80,6 +82,9 @@ func RunVmTest(p string, t *testing.T) { helper.CreateFileTests(t, p, &tests) for name, test := range tests { + if name != "log2_nonEmptyMem" { + continue + } db, _ := ethdb.NewMemDatabase() statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { @@ -167,16 +172,16 @@ func RunVmTest(p string, t *testing.T) { if len(test.Logs) != len(logs) { t.Errorf("log length mismatch. Expected %d, got %d", len(test.Logs), len(logs)) } else { - /* - fmt.Println("A", test.Logs) - fmt.Println("B", logs) - for i, log := range test.Logs { - genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) - if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { - t.Errorf("bloom mismatch") - } - } - */ + fmt.Println("A", test.Logs) + fmt.Println("B", logs) + for i, log := range test.Logs { + genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) + fmt.Println("A BLOOM", log.BloomF) + fmt.Printf("B BLOOM %x\n", genBloom) + if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { + t.Errorf("'%s' bloom mismatch", name) + } + } } } //statedb.Trie().PrintRoot() diff --git a/vm/environment.go b/vm/environment.go index fdce526ee..5d493166c 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -88,5 +88,5 @@ func (self *Log) RlpData() interface{} { */ func (self *Log) String() string { - return fmt.Sprintf("[A=%x T=%x D=%x]", self.address, self.topics, self.data) + return fmt.Sprintf("{%x %x %x}", self.address, self.data, self.topics) } From 86661de07746cd4e4ad8d016afee9fa8074aa141 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Mar 2015 18:00:03 +0100 Subject: [PATCH 27/78] Fixed tests and bloom --- core/types/bloom9.go | 17 ++++++++++------- core/types/common.go | 11 +++++++---- tests/vm/gh_test.go | 26 ++++++++++++++++++-------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/core/types/bloom9.go b/core/types/bloom9.go index 59b6c69c3..64a8ff49a 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -20,15 +20,15 @@ func CreateBloom(receipts Receipts) Bloom { func LogsBloom(logs state.Logs) *big.Int { bin := new(big.Int) for _, log := range logs { - data := make([]common.Hash, len(log.Topics())+1) - data[0] = log.Address().Hash() + data := make([]common.Hash, len(log.Topics())) + bin.Or(bin, bloom9(log.Address().Bytes())) for i, topic := range log.Topics() { - data[i+1] = topic + data[i] = topic } for _, b := range data { - bin.Or(bin, bloom9(crypto.Sha3(b[:]))) + bin.Or(bin, bloom9(b[:])) } } @@ -36,21 +36,24 @@ func LogsBloom(logs state.Logs) *big.Int { } func bloom9(b []byte) *big.Int { + b = crypto.Sha3(b[:]) + r := new(big.Int) for i := 0; i < 6; i += 2 { t := big.NewInt(1) - //b := uint(b[i+1]) + 512*(uint(b[i])&1) - b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 511 + b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 2047 r.Or(r, t.Lsh(t, b)) } return r } +var Bloom9 = bloom9 + func BloomLookup(bin Bloom, topic common.Hash) bool { bloom := bin.Big() - cmp := bloom9(crypto.Sha3(topic[:])) + cmp := bloom9(topic[:]) return bloom.And(bloom, cmp).Cmp(cmp) == 0 } diff --git a/core/types/common.go b/core/types/common.go index 6c5ac06b1..cb57ef053 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -10,7 +11,9 @@ type BlockProcessor interface { Process(*Block) (*big.Int, error) } -type Bloom [256]byte +const bloomLength = 256 + +type Bloom [bloomLength]byte func BytesToBloom(b []byte) Bloom { var bloom Bloom @@ -19,13 +22,13 @@ func BytesToBloom(b []byte) Bloom { } func (b *Bloom) SetBytes(d []byte) { - if len(b) > len(d) { - panic("bloom bytes too big") + if len(b) < len(d) { + panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d))) } // reverse loop for i := len(d) - 1; i >= 0; i-- { - b[i] = b[i] + b[bloomLength-len(d)+i] = b[i] } } diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go index bce34bb5d..68600d304 100644 --- a/tests/vm/gh_test.go +++ b/tests/vm/gh_test.go @@ -2,7 +2,6 @@ package vm import ( "bytes" - "fmt" "math/big" "strconv" "testing" @@ -82,9 +81,6 @@ func RunVmTest(p string, t *testing.T) { helper.CreateFileTests(t, p, &tests) for name, test := range tests { - if name != "log2_nonEmptyMem" { - continue - } db, _ := ethdb.NewMemDatabase() statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { @@ -172,12 +168,26 @@ func RunVmTest(p string, t *testing.T) { if len(test.Logs) != len(logs) { t.Errorf("log length mismatch. Expected %d, got %d", len(test.Logs), len(logs)) } else { - fmt.Println("A", test.Logs) - fmt.Println("B", logs) for i, log := range test.Logs { + if common.HexToAddress(log.AddressF) != logs[i].Address() { + t.Errorf("'%s' log address expected %v got %x", name, log.AddressF, logs[i].Address()) + } + + if !bytes.Equal(logs[i].Data(), helper.FromHex(log.DataF)) { + t.Errorf("'%s' log data expected %v got %x", name, log.DataF, logs[i].Data()) + } + + if len(log.TopicsF) != len(logs[i].Topics()) { + t.Errorf("'%s' log topics length expected %d got %d", name, len(log.TopicsF), logs[i].Topics()) + } else { + for j, topic := range log.TopicsF { + if common.HexToHash(topic) != logs[i].Topics()[j] { + t.Errorf("'%s' log topic[%d] expected %v got %x", name, j, topic, logs[i].Topics()[j]) + } + } + } genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) - fmt.Println("A BLOOM", log.BloomF) - fmt.Printf("B BLOOM %x\n", genBloom) + if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { t.Errorf("'%s' bloom mismatch", name) } From cb009a5c4da40e1987b9dfcffa4d52bcae41e4e1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Mar 2015 23:49:49 +0100 Subject: [PATCH 28/78] rlp: don't panic for nil *big.Int All other pointer types can handle nil just fine. --- rlp/encode.go | 7 ++++++- rlp/encode_test.go | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rlp/encode.go b/rlp/encode.go index 9d11d66bf..42bbb876c 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -386,7 +386,12 @@ func writeUint(val reflect.Value, w *encbuf) error { } func writeBigIntPtr(val reflect.Value, w *encbuf) error { - return writeBigInt(val.Interface().(*big.Int), w) + ptr := val.Interface().(*big.Int) + if ptr == nil { + w.str = append(w.str, 0x80) + return nil + } + return writeBigInt(ptr, w) } func writeBigIntNoPtr(val reflect.Value, w *encbuf) error { diff --git a/rlp/encode_test.go b/rlp/encode_test.go index c283fbd57..852cb6f59 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -196,6 +196,7 @@ var encTests = []encTest{ {val: (*uint)(nil), output: "80"}, {val: (*string)(nil), output: "80"}, {val: (*[]byte)(nil), output: "80"}, + {val: (*big.Int)(nil), output: "80"}, {val: (*[]string)(nil), output: "C0"}, {val: (*[]interface{})(nil), output: "C0"}, {val: (*[]struct{ uint })(nil), output: "C0"}, From cd52ef315cf4d65cfb5282f72d795849266e3ab5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Mar 2015 11:44:17 +0100 Subject: [PATCH 29/78] Added Hex methods --- common/types.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/types.go b/common/types.go index da46db874..38044d5c8 100644 --- a/common/types.go +++ b/common/types.go @@ -27,6 +27,7 @@ func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } func (h Hash) Str() string { return string(h[:]) } func (h Hash) Bytes() []byte { return h[:] } func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) } +func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) } // Sets the hash to the value of b. If b is larger than len(h) it will panic func (h *Hash) SetBytes(b []byte) { @@ -65,6 +66,7 @@ func (a Address) Str() string { return string(a[:]) } func (a Address) Bytes() []byte { return a[:] } func (a Address) Big() *big.Int { return Bytes2Big(a[:]) } func (a Address) Hash() Hash { return BytesToHash(a[:]) } +func (a Address) Hex() string { return "0x" + Bytes2Hex(a[:]) } // Sets the address to the value of b. If b is larger than len(a) it will panic func (a *Address) SetBytes(b []byte) { From 942980609fb8a36873689bd3bd0a15488f327d56 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Mar 2015 11:44:25 +0100 Subject: [PATCH 30/78] conversions --- core/types/common.go | 4 ++++ tests/blocktest.go | 9 ++++----- xeth/state.go | 6 +++--- xeth/types.go | 38 +++++++++++++++++++------------------- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/core/types/common.go b/core/types/common.go index cb57ef053..ace9c2c4b 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -35,3 +35,7 @@ func (b *Bloom) SetBytes(d []byte) { func (b Bloom) Big() *big.Int { return common.Bytes2Big(b[:]) } + +func (b Bloom) Bytes() []byte { + return b[:] +} diff --git a/tests/blocktest.go b/tests/blocktest.go index e4d001089..44b459c8d 100644 --- a/tests/blocktest.go +++ b/tests/blocktest.go @@ -13,7 +13,6 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" @@ -99,7 +98,7 @@ func LoadBlockTests(file string) (map[string]*BlockTest, error) { // InsertPreState populates the given database with the genesis // accounts defined by the test. func (t *BlockTest) InsertPreState(db common.Database) error { - statedb := state.New(nil, db) + statedb := state.New(common.Hash{}, db) for addrString, acct := range t.preAccounts { // XXX: is is worth it checking for errors here? //addr, _ := hex.DecodeString(addrString) @@ -120,7 +119,7 @@ func (t *BlockTest) InsertPreState(db common.Database) error { // sync trie to disk statedb.Sync() - if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root()) { + if t.Genesis.Root() != statedb.Root() { return errors.New("computed state root does not match genesis block") } return nil @@ -212,12 +211,12 @@ func mustConvertAddress(in string) common.Address { return common.BytesToAddress(out) } -func mustConvertBloom(in string) core.Bloom { +func mustConvertBloom(in string) types.Bloom { out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) if err != nil { panic(fmt.Errorf("invalid hex: %q", in)) } - return core.BytesToBloom(out) + return types.BytesToBloom(out) } func mustConvertBigInt10(in string) *big.Int { diff --git a/xeth/state.go b/xeth/state.go index 7d9ceab1b..f645a9cac 100644 --- a/xeth/state.go +++ b/xeth/state.go @@ -19,7 +19,7 @@ func (self *State) State() *state.StateDB { } func (self *State) Get(addr string) *Object { - return &Object{self.state.GetStateObject(common.FromHex(addr))} + return &Object{self.state.GetStateObject(common.HexToAddress(addr))} } func (self *State) SafeGet(addr string) *Object { @@ -27,9 +27,9 @@ func (self *State) SafeGet(addr string) *Object { } func (self *State) safeGet(addr string) *state.StateObject { - object := self.state.GetStateObject(common.FromHex(addr)) + object := self.state.GetStateObject(common.HexToAddress(addr)) if object == nil { - object = state.NewStateObject(common.FromHex(addr), self.xeth.eth.StateDb()) + object = state.NewStateObject(common.HexToAddress(addr), self.xeth.eth.StateDb()) } return object diff --git a/xeth/types.go b/xeth/types.go index e15305481..d6d2a11f7 100644 --- a/xeth/types.go +++ b/xeth/types.go @@ -5,10 +5,10 @@ import ( "fmt" "strings" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" @@ -59,19 +59,19 @@ func (self *Object) Storage() (storage map[string]string) { type Block struct { //Transactions string `json:"transactions"` ref *types.Block - Size string `json:"size"` - Number int `json:"number"` - Hash string `json:"hash"` + Size string `json:"size"` + Number int `json:"number"` + Hash string `json:"hash"` Transactions *common.List `json:"transactions"` Uncles *common.List `json:"uncles"` - Time int64 `json:"time"` - Coinbase string `json:"coinbase"` - Name string `json:"name"` - GasLimit string `json:"gasLimit"` - GasUsed string `json:"gasUsed"` - PrevHash string `json:"prevHash"` - Bloom string `json:"bloom"` - Raw string `json:"raw"` + Time int64 `json:"time"` + Coinbase string `json:"coinbase"` + Name string `json:"name"` + GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` + PrevHash string `json:"prevHash"` + Bloom string `json:"bloom"` + Raw string `json:"raw"` } // Creates a new QML Block from a chain block @@ -95,12 +95,12 @@ func NewBlock(block *types.Block) *Block { return &Block{ ref: block, Size: block.Size().String(), Number: int(block.NumberU64()), GasUsed: block.GasUsed().String(), - GasLimit: block.GasLimit().String(), Hash: toHex(block.Hash()), + GasLimit: block.GasLimit().String(), Hash: toHex(block.Hash().Bytes()), Transactions: txlist, Uncles: ulist, Time: block.Time(), - Coinbase: toHex(block.Coinbase()), - PrevHash: toHex(block.ParentHash()), - Bloom: toHex(block.Bloom()), + Coinbase: toHex(block.Coinbase().Bytes()), + PrevHash: toHex(block.ParentHash().Bytes()), + Bloom: toHex(block.Bloom().Bytes()), Raw: block.String(), } } @@ -114,7 +114,7 @@ func (self *Block) ToString() string { } func (self *Block) GetTransaction(hash string) *Transaction { - tx := self.ref.Transaction(common.FromHex(hash)) + tx := self.ref.Transaction(common.HexToHash(hash)) if tx == nil { return nil } @@ -139,8 +139,8 @@ type Transaction struct { } func NewTx(tx *types.Transaction) *Transaction { - hash := toHex(tx.Hash()) - receiver := toHex(tx.To()) + hash := tx.Hash().Hex() + receiver := tx.To().Hex() if len(receiver) == 0 { receiver = toHex(core.AddressFromMessage(tx)) } From 0a1eeca41e6ba5920ba65d9b41654768299bc7e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Mar 2015 13:00:01 +0100 Subject: [PATCH 31/78] conversions. -compilable- --- cmd/ethereum/admin.go | 4 +-- cmd/ethereum/main.go | 2 +- core/state_transition.go | 6 ++++ eth/backend.go | 10 +++--- eth/protocol.go | 61 +++++++++++++++---------------- miner/miner.go | 3 +- miner/worker.go | 27 +++++++------- rpc/api.go | 19 +++++----- rpc/responses.go | 77 +++++++++++++++++++++------------------- rpc/util.go | 4 +-- xeth/types.go | 6 ++-- xeth/xeth.go | 50 ++++++++++++-------------- 12 files changed, 139 insertions(+), 130 deletions(-) diff --git a/cmd/ethereum/admin.go b/cmd/ethereum/admin.go index 880a22c22..967af2553 100644 --- a/cmd/ethereum/admin.go +++ b/cmd/ethereum/admin.go @@ -8,8 +8,8 @@ import ( "time" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/state" @@ -239,7 +239,7 @@ func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value { block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num)) } else if call.Argument(0).IsString() { hash, _ := call.Argument(0).ToString() - block = js.ethereum.ChainManager().GetBlock(common.Hex2Bytes(hash)) + block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash)) } else { fmt.Println("invalid argument for dump. Either hex string or number") } diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 3b952dd79..459059e6c 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -302,7 +302,7 @@ func dump(ctx *cli.Context) { for _, arg := range ctx.Args() { var block *types.Block if hashish(arg) { - block = chainmgr.GetBlock(common.Hex2Bytes(arg)) + block = chainmgr.GetBlock(common.HexToHash(arg)) } else { num, _ := strconv.Atoi(arg) block = chainmgr.GetBlockByNumber(uint64(num)) diff --git a/core/state_transition.go b/core/state_transition.go index 1509a5258..d0b2c5d7c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -57,6 +57,12 @@ type Message interface { Data() []byte } +func AddressFromMessage(msg Message) common.Address { + from, _ := msg.From() + + return crypto.CreateAddress(from, msg.Nonce()) +} + func MessageCreatesContract(msg Message) bool { return msg.To() == nil } diff --git a/eth/backend.go b/eth/backend.go index 18093008b..c26bdceb5 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -10,11 +10,11 @@ import ( "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/blockpool" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/miner" @@ -288,7 +288,7 @@ func (s *Ethereum) StartMining() error { servlogger.Errorf("Cannot start mining without coinbase: %v\n", err) return fmt.Errorf("no coinbase: %v", err) } - s.miner.Start(cb) + s.miner.Start(common.BytesToAddress(cb)) return nil } @@ -304,9 +304,9 @@ func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } func (s *Ethereum) BlockPool() *blockpool.BlockPool { return s.blockPool } func (s *Ethereum) Whisper() *whisper.Whisper { return s.whisper } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } -func (s *Ethereum) BlockDb() common.Database { return s.blockDb } -func (s *Ethereum) StateDb() common.Database { return s.stateDb } -func (s *Ethereum) ExtraDb() common.Database { return s.extraDb } +func (s *Ethereum) BlockDb() common.Database { return s.blockDb } +func (s *Ethereum) StateDb() common.Database { return s.stateDb } +func (s *Ethereum) ExtraDb() common.Database { return s.extraDb } func (s *Ethereum) IsListening() bool { return true } // Always listening func (s *Ethereum) PeerCount() int { return s.net.PeerCount() } func (s *Ethereum) PeerInfo() int { return s.net.PeerCount() } diff --git a/eth/protocol.go b/eth/protocol.go index e368bbec5..15a8e1831 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -1,13 +1,12 @@ package eth import ( - "bytes" "fmt" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" @@ -76,15 +75,15 @@ type txPool interface { } type chainManager interface { - GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) - GetBlock(hash []byte) (block *types.Block) - Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) + GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash) + GetBlock(hash common.Hash) (block *types.Block) + Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) } type blockPool interface { - AddBlockHashes(next func() ([]byte, bool), peerId string) + AddBlockHashes(next func() (common.Hash, bool), peerId string) AddBlock(block *types.Block, peerId string) - AddPeer(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool) + AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) RemovePeer(peerId string) } @@ -95,7 +94,7 @@ type newBlockMsgData struct { } type getBlockHashesMsgData struct { - Hash []byte + Hash common.Hash Amount uint64 } @@ -167,7 +166,7 @@ func (self *ethProtocol) handle() error { } for _, tx := range txs { jsonlogger.LogJson(&logger.EthTxReceived{ - TxHash: common.Bytes2Hex(tx.Hash()), + TxHash: tx.Hash().Hex(), RemoteId: self.peer.ID().String(), }) } @@ -183,7 +182,7 @@ func (self *ethProtocol) handle() error { request.Amount = maxHashes } hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount) - return p2p.EncodeMsg(self.rw, BlockHashesMsg, common.ByteSliceToInterface(hashes)...) + return p2p.EncodeMsg(self.rw, BlockHashesMsg, rlp.Flat(hashes)) case BlockHashesMsg: msgStream := rlp.NewStream(msg.Payload) @@ -192,14 +191,16 @@ func (self *ethProtocol) handle() error { } var i int - iter := func() (hash []byte, ok bool) { - hash, err := msgStream.Bytes() + iter := func() (hash common.Hash, ok bool) { + var h common.Hash + err := msgStream.Decode(&h) if err == rlp.EOL { - return nil, false + return common.Hash{}, false } else if err != nil { self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err) - return nil, false + return common.Hash{}, false } + i++ return hash, true } @@ -215,14 +216,14 @@ func (self *ethProtocol) handle() error { var i int for { i++ - var hash []byte - if err := msgStream.Decode(&hash); err != nil { - if err == rlp.EOL { - break - } else { - return self.protoError(ErrDecode, "msg %v: %v", msg, err) - } + var hash common.Hash + err := msgStream.Decode(&hash) + if err == rlp.EOL { + break + } else { + return self.protoError(ErrDecode, "msg %v: %v", msg, err) } + block := self.chainManager.GetBlock(hash) if block != nil { blocks = append(blocks, block) @@ -259,10 +260,10 @@ func (self *ethProtocol) handle() error { _, chainHead, _ := self.chainManager.Status() jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{ - BlockHash: common.Bytes2Hex(hash), + BlockHash: hash.Hex(), BlockNumber: request.Block.Number(), // this surely must be zero - ChainHeadHash: common.Bytes2Hex(chainHead), - BlockPrevHash: common.Bytes2Hex(request.Block.ParentHash()), + ChainHeadHash: chainHead.Hex(), + BlockPrevHash: request.Block.ParentHash().Hex(), RemoteId: self.peer.ID().String(), }) // to simplify backend interface adding a new block @@ -282,8 +283,8 @@ type statusMsgData struct { ProtocolVersion uint32 NetworkId uint32 TD *big.Int - CurrentBlock []byte - GenesisBlock []byte + CurrentBlock common.Hash + GenesisBlock common.Hash } func (self *ethProtocol) statusMsg() p2p.Msg { @@ -325,7 +326,7 @@ func (self *ethProtocol) handleStatus() error { _, _, genesisBlock := self.chainManager.Status() - if !bytes.Equal(status.GenesisBlock, genesisBlock) { + if status.GenesisBlock != genesisBlock { return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock) } @@ -344,14 +345,14 @@ func (self *ethProtocol) handleStatus() error { return nil } -func (self *ethProtocol) requestBlockHashes(from []byte) error { +func (self *ethProtocol) requestBlockHashes(from common.Hash) error { self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4]) return p2p.EncodeMsg(self.rw, GetBlockHashesMsg, interface{}(from), uint64(maxHashes)) } -func (self *ethProtocol) requestBlocks(hashes [][]byte) error { +func (self *ethProtocol) requestBlocks(hashes []common.Hash) error { self.peer.Debugf("fetching %v blocks", len(hashes)) - return p2p.EncodeMsg(self.rw, GetBlocksMsg, common.ByteSliceToInterface(hashes)...) + return p2p.EncodeMsg(self.rw, GetBlocksMsg, rlp.Flat(hashes)) } func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) { diff --git a/miner/miner.go b/miner/miner.go index 7bf67a6ec..ccc19c754 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/ethereum/ethash" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" @@ -32,7 +33,7 @@ func (self *Miner) Mining() bool { return self.mining } -func (self *Miner) Start(coinbase []byte) { +func (self *Miner) Start(coinbase common.Address) { self.mining = true self.worker = newWorker(coinbase, self.eth) self.worker.register(NewCpuMiner(0, self.pow)) diff --git a/miner/worker.go b/miner/worker.go index 10fc6f508..63d1bfa0b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -7,9 +7,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" @@ -39,7 +39,7 @@ func env(block *types.Block, eth core.Backend) *environment { coinbase: state.GetOrNewStateObject(block.Coinbase()), } for _, ancestor := range eth.ChainManager().GetAncestors(block, 7) { - env.ancestors.Add(string(ancestor.Hash())) + env.ancestors.Add(ancestor.Hash()) } return env @@ -71,14 +71,14 @@ type worker struct { eth core.Backend chain *core.ChainManager proc *core.BlockProcessor - coinbase []byte + coinbase common.Address current *environment mining bool } -func newWorker(coinbase []byte, eth core.Backend) *worker { +func newWorker(coinbase common.Address, eth core.Backend) *worker { return &worker{ eth: eth, mux: eth.EventMux(), @@ -152,13 +152,13 @@ func (self *worker) wait() { block := self.current.block if block.Number().Uint64() == work.Number && block.Nonce() == 0 { self.current.block.SetNonce(work.Nonce) - self.current.block.Header().MixDigest = work.MixDigest + self.current.block.Header().MixDigest = common.BytesToHash(work.MixDigest) jsonlogger.LogJson(&logger.EthMinerNewBlock{ - BlockHash: common.Bytes2Hex(block.Hash()), + BlockHash: block.Hash().Hex(), BlockNumber: block.Number(), - ChainHeadHash: common.Bytes2Hex(block.ParentHeaderHash), - BlockPrevHash: common.Bytes2Hex(block.ParentHeaderHash), + ChainHeadHash: block.ParentHeaderHash.Hex(), + BlockPrevHash: block.ParentHeaderHash.Hex(), }) if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil { @@ -208,9 +208,10 @@ gasLimit: fallthrough case core.IsInvalidTxErr(err): // Remove invalid transactions - self.chain.TxState().RemoveNonce(tx.From(), tx.Nonce()) + from, _ := tx.From() + self.chain.TxState().RemoveNonce(from, tx.Nonce()) remove = append(remove, tx) - minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash()[:4]) + minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash().Bytes()[:4]) case state.IsGasLimitErr(err): minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i) // Break on gas limit @@ -232,13 +233,13 @@ var ( ) func (self *worker) commitUncle(uncle *types.Header) error { - if self.current.uncles.Has(string(uncle.Hash())) { + if self.current.uncles.Has(uncle.Hash()) { // Error not unique return core.UncleError("Uncle not unique") } - self.current.uncles.Add(string(uncle.Hash())) + self.current.uncles.Add(uncle.Hash()) - if !self.current.ancestors.Has(string(uncle.ParentHash)) { + if !self.current.ancestors.Has(uncle.ParentHash) { return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } diff --git a/rpc/api.go b/rpc/api.go index 079347192..3c46684d1 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -668,7 +668,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return NewValidationError("Index", "does not exist") } - uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false) + uncle, err := p.GetBlockByHash(v.Uncles[args.Index].Hex(), false) if err != nil { return err } @@ -687,7 +687,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return NewValidationError("Index", "does not exist") } - uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false) + uncle, err := p.GetBlockByHash(v.Uncles[args.Index].Hex(), false) if err != nil { return err } @@ -832,12 +832,12 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions { // Convert optional address slice/string to byte slice if str, ok := options.Address.(string); ok { - opts.Address = [][]byte{common.FromHex(str)} + opts.Address = []common.Address{common.HexToAddress(str)} } else if slice, ok := options.Address.([]interface{}); ok { - bslice := make([][]byte, len(slice)) + bslice := make([]common.Address, len(slice)) for i, addr := range slice { if saddr, ok := addr.(string); ok { - bslice[i] = common.FromHex(saddr) + bslice[i] = common.HexToAddress(saddr) } } opts.Address = bslice @@ -846,16 +846,15 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions { opts.Earliest = options.Earliest opts.Latest = options.Latest - topics := make([][][]byte, len(options.Topics)) + topics := make([][]common.Hash, len(options.Topics)) for i, topicDat := range options.Topics { if slice, ok := topicDat.([]interface{}); ok { - topics[i] = make([][]byte, len(slice)) + topics[i] = make([]common.Hash, len(slice)) for j, topic := range slice { - topics[i][j] = common.FromHex(topic.(string)) + topics[i][j] = common.HexToHash(topic.(string)) } } else if str, ok := topicDat.(string); ok { - topics[i] = make([][]byte, 1) - topics[i][0] = common.FromHex(str) + topics[i] = []common.Hash{common.HexToHash(str)} } } opts.Topics = topics diff --git a/rpc/responses.go b/rpc/responses.go index f41ce7b96..5b2b9d488 100644 --- a/rpc/responses.go +++ b/rpc/responses.go @@ -5,6 +5,7 @@ import ( // "fmt" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -12,14 +13,14 @@ type BlockRes struct { fullTx bool BlockNumber int64 `json:"number"` - BlockHash []byte `json:"hash"` - ParentHash []byte `json:"parentHash"` - Nonce []byte `json:"nonce"` - Sha3Uncles []byte `json:"sha3Uncles"` - LogsBloom []byte `json:"logsBloom"` - TransactionRoot []byte `json:"transactionRoot"` - StateRoot []byte `json:"stateRoot"` - Miner []byte `json:"miner"` + BlockHash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash"` + Nonce [8]byte `json:"nonce"` + Sha3Uncles common.Hash `json:"sha3Uncles"` + LogsBloom types.Bloom `json:"logsBloom"` + TransactionRoot common.Hash `json:"transactionRoot"` + StateRoot common.Hash `json:"stateRoot"` + Miner common.Address `json:"miner"` Difficulty int64 `json:"difficulty"` TotalDifficulty int64 `json:"totalDifficulty"` Size int64 `json:"size"` @@ -29,7 +30,7 @@ type BlockRes struct { GasUsed int64 `json:"gasUsed"` UnixTimestamp int64 `json:"timestamp"` Transactions []*TransactionRes `json:"transactions"` - Uncles [][]byte `json:"uncles"` + Uncles []common.Hash `json:"uncles"` } func (b *BlockRes) MarshalJSON() ([]byte, error) { @@ -57,14 +58,14 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { // convert strict types to hexified strings ext.BlockNumber = toHex(big.NewInt(b.BlockNumber).Bytes()) - ext.BlockHash = toHex(b.BlockHash) - ext.ParentHash = toHex(b.ParentHash) - ext.Nonce = toHex(b.Nonce) - ext.Sha3Uncles = toHex(b.Sha3Uncles) - ext.LogsBloom = toHex(b.LogsBloom) - ext.TransactionRoot = toHex(b.TransactionRoot) - ext.StateRoot = toHex(b.StateRoot) - ext.Miner = toHex(b.Miner) + ext.BlockHash = b.BlockHash.Hex() + ext.ParentHash = b.ParentHash.Hex() + ext.Nonce = toHex(b.Nonce[:]) + ext.Sha3Uncles = b.Sha3Uncles.Hex() + ext.LogsBloom = toHex(b.LogsBloom[:]) + ext.TransactionRoot = b.TransactionRoot.Hex() + ext.StateRoot = b.StateRoot.Hex() + ext.Miner = b.Miner.Hex() ext.Difficulty = toHex(big.NewInt(b.Difficulty).Bytes()) ext.TotalDifficulty = toHex(big.NewInt(b.TotalDifficulty).Bytes()) ext.Size = toHex(big.NewInt(b.Size).Bytes()) @@ -80,12 +81,12 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { } } else { for i, tx := range b.Transactions { - ext.Transactions[i] = toHex(tx.Hash) + ext.Transactions[i] = tx.Hash.Hex() } } ext.Uncles = make([]string, len(b.Uncles)) for i, v := range b.Uncles { - ext.Uncles[i] = toHex(v) + ext.Uncles[i] = v.Hex() } return json.Marshal(ext) @@ -124,7 +125,7 @@ func NewBlockRes(block *types.Block) *BlockRes { v.TxIndex = int64(i) res.Transactions[i] = v } - res.Uncles = make([][]byte, len(block.Uncles())) + res.Uncles = make([]common.Hash, len(block.Uncles())) for i, uncle := range block.Uncles() { res.Uncles[i] = uncle.Hash() } @@ -132,17 +133,17 @@ func NewBlockRes(block *types.Block) *BlockRes { } type TransactionRes struct { - Hash []byte `json:"hash"` - Nonce int64 `json:"nonce"` - BlockHash []byte `json:"blockHash,omitempty"` - BlockNumber int64 `json:"blockNumber,omitempty"` - TxIndex int64 `json:"transactionIndex,omitempty"` - From []byte `json:"from"` - To []byte `json:"to"` - Value int64 `json:"value"` - Gas int64 `json:"gas"` - GasPrice int64 `json:"gasPrice"` - Input []byte `json:"input"` + Hash common.Hash `json:"hash"` + Nonce int64 `json:"nonce"` + BlockHash common.Hash `json:"blockHash,omitempty"` + BlockNumber int64 `json:"blockNumber,omitempty"` + TxIndex int64 `json:"transactionIndex,omitempty"` + From common.Address `json:"from"` + To *common.Address `json:"to"` + Value int64 `json:"value"` + Gas int64 `json:"gas"` + GasPrice int64 `json:"gasPrice"` + Input []byte `json:"input"` } func (t *TransactionRes) MarshalJSON() ([]byte, error) { @@ -160,13 +161,17 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) { Input string `json:"input"` } - ext.Hash = toHex(t.Hash) + ext.Hash = t.Hash.Hex() ext.Nonce = toHex(big.NewInt(t.Nonce).Bytes()) - ext.BlockHash = toHex(t.BlockHash) + ext.BlockHash = t.BlockHash.Hex() ext.BlockNumber = toHex(big.NewInt(t.BlockNumber).Bytes()) ext.TxIndex = toHex(big.NewInt(t.TxIndex).Bytes()) - ext.From = toHex(t.From) - ext.To = toHex(t.To) + ext.From = t.From.Hex() + if t.To == nil { + ext.To = "0x00" + } else { + ext.To = t.To.Hex() + } ext.Value = toHex(big.NewInt(t.Value).Bytes()) ext.Gas = toHex(big.NewInt(t.Gas).Bytes()) ext.GasPrice = toHex(big.NewInt(t.GasPrice).Bytes()) @@ -179,7 +184,7 @@ func NewTransactionRes(tx *types.Transaction) *TransactionRes { var v = new(TransactionRes) v.Hash = tx.Hash() v.Nonce = int64(tx.Nonce()) - v.From = tx.From() + v.From, _ = tx.From() v.To = tx.To() v.Value = tx.Value().Int64() v.Gas = tx.Gas().Int64() diff --git a/rpc/util.go b/rpc/util.go index e5610dc2c..b9b0fa442 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -155,11 +155,11 @@ func toLogs(logs state.Logs) (ls []Log) { for i, log := range logs { var l Log l.Topic = make([]string, len(log.Topics())) - l.Address = toHex(log.Address()) + l.Address = log.Address().Hex() l.Data = toHex(log.Data()) l.Number = log.Number() for j, topic := range log.Topics() { - l.Topic[j] = toHex(topic) + l.Topic[j] = topic.Hex() } ls[i] = l } diff --git a/xeth/types.go b/xeth/types.go index d6d2a11f7..d8d6ff19f 100644 --- a/xeth/types.go +++ b/xeth/types.go @@ -142,9 +142,9 @@ func NewTx(tx *types.Transaction) *Transaction { hash := tx.Hash().Hex() receiver := tx.To().Hex() if len(receiver) == 0 { - receiver = toHex(core.AddressFromMessage(tx)) + receiver = core.AddressFromMessage(tx).Hex() } - sender := toHex(tx.From()) + sender, _ := tx.From() createsContract := core.MessageCreatesContract(tx) var data string @@ -154,7 +154,7 @@ func NewTx(tx *types.Transaction) *Transaction { data = toHex(tx.Data()) } - return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: toHex(tx.Data())} + return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender.Hex(), CreatesContract: createsContract, RawData: toHex(tx.Data())} } func (self *Transaction) ToString() string { diff --git a/xeth/xeth.go b/xeth/xeth.go index 6c7a26c04..672b83332 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -8,10 +8,10 @@ import ( "math/big" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p" @@ -116,14 +116,14 @@ func (self *XEth) State() *State { return self.state } func (self *XEth) Whisper() *Whisper { return self.whisper } func (self *XEth) BlockByHash(strHash string) *Block { - hash := common.FromHex(strHash) + hash := common.HexToHash(strHash) block := self.chainManager.GetBlock(hash) return NewBlock(block) } func (self *XEth) EthBlockByHash(strHash string) *types.Block { - hash := common.FromHex(strHash) + hash := common.HexToHash(strHash) block := self.chainManager.GetBlock(hash) return block @@ -293,9 +293,9 @@ func (self *XEth) PushTx(encodedTx string) (string, error) { if tx.To() == nil { addr := core.AddressFromMessage(tx) - return toHex(addr), nil + return addr.Hex(), nil } - return toHex(tx.Hash()), nil + return tx.Hash().Hex(), nil } var ( @@ -306,8 +306,8 @@ var ( func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) { statedb := self.State().State() //self.chainManager.TransState() msg := callmsg{ - from: statedb.GetOrNewStateObject(common.FromHex(fromStr)), - to: common.FromHex(toStr), + from: statedb.GetOrNewStateObject(common.HexToAddress(fromStr)), + to: common.HexToAddress(toStr), gas: common.Big(gasStr), gasPrice: common.Big(gasPriceStr), value: common.Big(valueStr), @@ -330,8 +330,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { var ( - from []byte - to []byte + from = common.HexToAddress(fromStr) + to = common.HexToAddress(toStr) value = common.NewValue(valueStr) gas = common.NewValue(gasStr) price = common.NewValue(gasPriceStr) @@ -339,10 +339,8 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt contractCreation bool ) - from = common.FromHex(fromStr) data = common.FromHex(codeStr) - to = common.FromHex(toStr) - if len(to) == 0 { + if len(toStr) == 0 { contractCreation = true } @@ -368,21 +366,19 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt if contractCreation { addr := core.AddressFromMessage(tx) pipelogger.Infof("Contract addr %x\n", addr) - } - if types.IsContractAddr(to) { - return toHex(core.AddressFromMessage(tx)), nil + return core.AddressFromMessage(tx).Hex(), nil } - return toHex(tx.Hash()), nil + return tx.Hash().Hex(), nil } -func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error { - sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash()) +func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock bool) error { + sig, err := self.accountManager.Sign(accounts.Account{Address: from.Bytes()}, tx.Hash().Bytes()) if err == accounts.ErrLocked { if didUnlock { return fmt.Errorf("sender account still locked after successful unlock") } - if !self.frontend.UnlockAccount(from) { + if !self.frontend.UnlockAccount(from.Bytes()) { return fmt.Errorf("could not unlock sender account") } // retry signing, the account should now be unlocked. @@ -397,17 +393,17 @@ func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error // callmsg is the message type used for call transations. type callmsg struct { from *state.StateObject - to []byte + to common.Address gas, gasPrice *big.Int value *big.Int data []byte } // accessor boilerplate to implement core.Message -func (m callmsg) From() []byte { return m.from.Address() } -func (m callmsg) Nonce() uint64 { return m.from.Nonce() } -func (m callmsg) To() []byte { return m.to } -func (m callmsg) GasPrice() *big.Int { return m.gasPrice } -func (m callmsg) Gas() *big.Int { return m.gas } -func (m callmsg) Value() *big.Int { return m.value } -func (m callmsg) Data() []byte { return m.data } +func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil } +func (m callmsg) Nonce() uint64 { return m.from.Nonce() } +func (m callmsg) To() *common.Address { return &m.to } +func (m callmsg) GasPrice() *big.Int { return m.gasPrice } +func (m callmsg) Gas() *big.Int { return m.gas } +func (m callmsg) Value() *big.Int { return m.value } +func (m callmsg) Data() []byte { return m.data } From b94a6a0193884ba2edb8eb38670e51b033893387 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Mar 2015 13:17:39 +0100 Subject: [PATCH 32/78] rlp: add DecodeBytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ãœber-convenience. --- rlp/decode.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rlp/decode.go b/rlp/decode.go index 55f7187a3..6d7e670c2 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -2,6 +2,7 @@ package rlp import ( "bufio" + "bytes" "encoding/binary" "errors" "fmt" @@ -73,6 +74,12 @@ func Decode(r io.Reader, val interface{}) error { return NewStream(r).Decode(val) } +// DecodeBytes parses RLP data from b into val. +// Please see the documentation of Decode for the decoding rules. +func DecodeBytes(b []byte, val interface{}) error { + return NewStream(bytes.NewReader(b)).Decode(val) +} + type decodeError struct { msg string typ reflect.Type From c298148a7f0890cd5ed62d2a91cc81431b2731f1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Mar 2015 13:24:34 +0100 Subject: [PATCH 33/78] core/types: use package rlp instead of common.Decode --- core/types/block.go | 101 +++++++++++++++++++++++++++++--------- core/types/block_test.go | 57 ++++++++++++++++++--- core/types/derive_sha.go | 4 +- core/types/transaction.go | 55 ++++++++++----------- 4 files changed, 156 insertions(+), 61 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index aca23aa04..6f26358fb 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -3,12 +3,13 @@ package types import ( "encoding/binary" "fmt" + "io" "math/big" "sort" "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" ) @@ -45,6 +46,14 @@ type Header struct { Nonce [8]byte } +func (self *Header) Hash() common.Hash { + return rlpHash(self.rlpData(true)) +} + +func (self *Header) HashNoNonce() common.Hash { + return rlpHash(self.rlpData(false)) +} + func (self *Header) rlpData(withNonce bool) []interface{} { fields := []interface{}{ self.ParentHash, @@ -64,7 +73,6 @@ func (self *Header) rlpData(withNonce bool) []interface{} { if withNonce { fields = append(fields, self.MixDigest, self.Nonce) } - return fields } @@ -72,12 +80,11 @@ func (self *Header) RlpData() interface{} { return self.rlpData(true) } -func (self *Header) Hash() common.Hash { - return common.BytesToHash(crypto.Sha3(common.Encode(self.rlpData(true)))) -} - -func (self *Header) HashNoNonce() common.Hash { - return common.BytesToHash(crypto.Sha3(common.Encode(self.rlpData(false)))) +func rlpHash(x interface{}) (h common.Hash) { + hw := sha3.NewKeccak256() + rlp.Encode(hw, x) + hw.Sum(h[:0]) + return h } type Block struct { @@ -95,6 +102,26 @@ type Block struct { Reward *big.Int } +// StorageBlock defines the RLP encoding of a Block stored in the +// state database. The StorageBlock encoding contains fields that +// would otherwise need to be recomputed. +type StorageBlock Block + +// "external" block encoding. used for eth protocol, etc. +type extblock struct { + Header *Header + Txs []*Transaction + Uncles []*Header +} + +// "storage" block encoding. used for database. +type storageblock struct { + Header *Header + Txs []*Transaction + Uncles []*Header + TD *big.Int +} + func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block { header := &Header{ Root: root, @@ -107,9 +134,7 @@ func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, GasLimit: new(big.Int), } header.SetNonce(nonce) - block := &Block{header: header, Reward: new(big.Int)} - return block } @@ -122,22 +147,40 @@ func NewBlockWithHeader(header *Header) *Block { } func (self *Block) DecodeRLP(s *rlp.Stream) error { - var extblock struct { - Header *Header - Txs []*Transaction - Uncles []*Header - TD *big.Int // optional - } - if err := s.Decode(&extblock); err != nil { + var eb extblock + if err := s.Decode(&eb); err != nil { return err } - self.header = extblock.Header - self.uncles = extblock.Uncles - self.transactions = extblock.Txs - self.Td = extblock.TD + self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs return nil } +func (self Block) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, extblock{ + Header: self.header, + Txs: self.transactions, + Uncles: self.uncles, + }) +} + +func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error { + var sb storageblock + if err := s.Decode(&sb); err != nil { + return err + } + self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD + return nil +} + +func (self StorageBlock) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, storageblock{ + Header: self.header, + Txs: self.transactions, + Uncles: self.uncles, + TD: self.Td, + }) +} + func (self *Block) Header() *Header { return self.header } @@ -148,7 +191,7 @@ func (self *Block) Uncles() []*Header { func (self *Block) SetUncles(uncleHeaders []*Header) { self.uncles = uncleHeaders - self.header.UncleHash = common.BytesToHash(crypto.Sha3(common.Encode(uncleHeaders))) + self.header.UncleHash = rlpHash(uncleHeaders) } func (self *Block) Transactions() Transactions { @@ -213,7 +256,6 @@ func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } func (self *Block) Root() common.Hash { return self.header.Root } func (self *Block) SetRoot(root common.Hash) { self.header.Root = root } -func (self *Block) Size() common.StorageSize { return common.StorageSize(len(common.Encode(self))) } func (self *Block) GetTransaction(i int) *Transaction { if len(self.transactions) > i { return self.transactions[i] @@ -227,6 +269,19 @@ func (self *Block) GetUncle(i int) *Header { return nil } +func (self *Block) Size() common.StorageSize { + c := writeCounter(0) + rlp.Encode(&c, self) + return common.StorageSize(c) +} + +type writeCounter common.StorageSize + +func (c *writeCounter) Write(b []byte) (int, error) { + *c += writeCounter(len(b)) + return len(b), nil +} + // Implement pow.Block func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() } diff --git a/core/types/block_test.go b/core/types/block_test.go index 16ba3043f..e4f6c38a5 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -1,19 +1,60 @@ package types import ( + "bytes" "math/big" + "reflect" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) -// XXX Tests doesn't really do anything. This tests exists while working on the fixed size conversions -func TestConversion(t *testing.T) { - var ( - parent common.Hash - coinbase common.Address - hash common.Hash - ) +// from bcValidBlockTest.json, "SimpleTx" +func TestBlockEncoding(t *testing.T) { + blockEnc := common.FromHex("f90260f901f9a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0") - NewBlock(parent, coinbase, hash, big.NewInt(0), 0, "") + var block Block + if err := rlp.DecodeBytes(blockEnc, &block); err != nil { + t.Fatal("decode error: ", err) + } + + check := func(f string, got, want interface{}) { + if !reflect.DeepEqual(got, want) { + t.Errorf("%s mismatch: got %v, want %v", f, got, want) + } + } + check("Difficulty", block.Difficulty(), big.NewInt(131072)) + check("GasLimit", block.GasLimit(), big.NewInt(3141592)) + check("GasUsed", block.GasUsed(), big.NewInt(21000)) + check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1")) + check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) + check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) + check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e")) + check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) + check("Time", block.Time(), int64(1426516743)) + check("Size", block.Size(), common.StorageSize(len(blockEnc))) + + to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") + check("Transactions", block.Transactions(), Transactions{ + { + Payload: []byte{}, + Amount: big.NewInt(10), + Price: big.NewInt(10), + GasLimit: big.NewInt(50000), + AccountNonce: 0, + V: 27, + R: common.FromHex("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f"), + S: common.FromHex("8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"), + Recipient: &to, + }, + }) + + ourBlockEnc, err := rlp.EncodeToBytes(&block) + if err != nil { + t.Fatal("encode error: ", err) + } + if !bytes.Equal(ourBlockEnc, blockEnc) { + t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc) + } } diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go index 0fc45a508..10e3d7446 100644 --- a/core/types/derive_sha.go +++ b/core/types/derive_sha.go @@ -3,6 +3,7 @@ package types import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -15,7 +16,8 @@ func DeriveSha(list DerivableList) common.Hash { db, _ := ethdb.NewMemDatabase() trie := trie.New(nil, db) for i := 0; i < list.Len(); i++ { - trie.Update(common.Encode(i), list.GetRlp(i)) + key, _ := rlp.EncodeToBytes(i) + trie.Update(key, list.GetRlp(i)) } return common.BytesToHash(trie.Root()) diff --git a/core/types/transaction.go b/core/types/transaction.go index 24035a3ae..391fb46f5 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -1,16 +1,14 @@ package types import ( - "bytes" + "crypto/ecdsa" "errors" "fmt" - "io" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" ) @@ -38,16 +36,18 @@ func NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.I } func NewTransactionFromBytes(data []byte) *Transaction { + // TODO: remove this function if possible. callers would + // much better off decoding into transaction directly. + // it's not that hard. tx := new(Transaction) - rlp.Decode(bytes.NewReader(data), tx) + rlp.DecodeBytes(data, tx) return tx } -func (tx *Transaction) Hash() (a common.Hash) { - h := sha3.NewKeccak256() - rlp.Encode(h, []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}) - h.Sum(a[:0]) - return a +func (tx *Transaction) Hash() common.Hash { + return rlpHash([]interface{}{ + tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload, + }) } func (self *Transaction) Data() []byte { @@ -122,17 +122,14 @@ func (tx *Transaction) SetSignatureValues(sig []byte) error { return nil } -func (tx Transaction) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, []interface{}{ - tx.AccountNonce, - tx.Price, tx.GasLimit, - tx.Recipient, - tx.Amount, - tx.Payload, - tx.V, - tx.R, - tx.S, - }) +func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) error { + h := tx.Hash() + sig, err := crypto.Sign(h[:], prv) + if err != nil { + return err + } + tx.SetSignatureValues(sig) + return nil } // TODO: remove @@ -141,11 +138,6 @@ func (tx *Transaction) RlpData() interface{} { return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes()) } -// TODO: remove -func (tx *Transaction) RlpEncode() []byte { - return common.Encode(tx) -} - func (tx *Transaction) String() string { var from, to string if f, err := tx.From(); err != nil { @@ -158,6 +150,7 @@ func (tx *Transaction) String() string { } else { to = fmt.Sprintf("%x", t[:]) } + enc, _ := rlp.EncodeToBytes(tx) return fmt.Sprintf(` TX(%x) Contract: %v @@ -185,7 +178,7 @@ func (tx *Transaction) String() string { tx.V, tx.R, tx.S, - common.Encode(tx), + enc, ) } @@ -204,9 +197,13 @@ func (self Transactions) RlpData() interface{} { return enc } -func (s Transactions) Len() int { return len(s) } -func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s Transactions) GetRlp(i int) []byte { return common.Rlp(s[i]) } +func (s Transactions) Len() int { return len(s) } +func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (s Transactions) GetRlp(i int) []byte { + enc, _ := rlp.EncodeToBytes(s[i]) + return enc +} type TxByNonce struct{ Transactions } From b5b83db450974f70f4bc25f280cc6ec9193f8e19 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Mar 2015 13:36:48 +0100 Subject: [PATCH 34/78] core: use package rlp to encode blocks This also changes the chain export format so there is no enclosing list around the blocks, which enables streaming export. --- cmd/utils/cmd.go | 37 ++++++++++++++++++++++--------------- core/chain_manager.go | 27 ++++++++++++--------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 74fd5334e..66e89abef 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -23,14 +23,15 @@ package utils import ( "fmt" + "io" "os" "os/signal" "regexp" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/rlp" ) @@ -152,29 +153,35 @@ func ImportChain(chainmgr *core.ChainManager, fn string) error { } defer fh.Close() - var blocks types.Blocks - if err := rlp.Decode(fh, &blocks); err != nil { - return err - } - chainmgr.Reset() - if err := chainmgr.InsertChain(blocks); err != nil { - return err + stream := rlp.NewStream(fh) + var i int + for ; ; i++ { + var b types.Block + err := stream.Decode(&b) + if err == io.EOF { + break + } else if err != nil { + return fmt.Errorf("at block %d: %v", i, err) + } + if err := chainmgr.InsertChain(types.Blocks{b}); err != nil { + return fmt.Errorf("invalid block %d: %v", i, err) + } } - fmt.Printf("imported %d blocks\n", len(blocks)) - + fmt.Printf("imported %d blocks\n", i) return nil } func ExportChain(chainmgr *core.ChainManager, fn string) error { fmt.Printf("exporting blockchain '%s'\n", fn) - - data := chainmgr.Export() - - if err := common.WriteFile(fn, data); err != nil { + fh, err := os.OpenFile(fn, os.O_WRONLY|os.O_TRUNC, os.ModePerm) + if err != nil { + return err + } + defer fh.Close() + if err := chainmgr.Export(fh); err != nil { return err } fmt.Printf("exported blockchain\n") - return nil } diff --git a/core/chain_manager.go b/core/chain_manager.go index 5316a3423..060805428 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -3,6 +3,7 @@ package core import ( "bytes" "fmt" + "io" "math/big" "sync" @@ -254,22 +255,20 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { bc.currentBlock = bc.genesisBlock } -func (self *ChainManager) Export() []byte { +// Export writes the active chain to the given writer. +func (self *ChainManager) Export(w io.Writer) error { self.mu.RLock() defer self.mu.RUnlock() - chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number) - - blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1) for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) { - blocks[block.NumberU64()] = block + if err := block.EncodeRLP(w); err != nil { + return err + } } - - return common.Encode(blocks) + return nil } func (bc *ChainManager) insert(block *types.Block) { - //encodedBlock := common.Encode(block) bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) bc.currentBlock = block bc.lastBlockHash = block.Hash() @@ -279,10 +278,9 @@ func (bc *ChainManager) insert(block *types.Block) { } func (bc *ChainManager) write(block *types.Block) { - encodedBlock := common.Encode(block.RlpDataForStorage()) - + enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) key := append(blockHashPre, block.Hash().Bytes()...) - bc.blockDb.Put(key, encodedBlock) + bc.blockDb.Put(key, enc) } // Accessors @@ -324,13 +322,12 @@ func (self *ChainManager) GetBlock(hash common.Hash) *types.Block { if len(data) == 0 { return nil } - var block types.Block + var block types.StorageBlock if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { - fmt.Println(err) + chainlogger.Errorf("invalid block RLP for hash %x: %v", hash, err) return nil } - - return &block + return (*types.Block)(&block) } func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { From a59dd393e71cc52b1f96973aef884af619166f38 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Mar 2015 13:38:47 +0100 Subject: [PATCH 35/78] core: fix tests --- core/block_processor_test.go | 5 +++-- core/chain_manager_test.go | 9 ++++----- core/genesis.go | 4 ---- core/transaction_pool.go | 2 +- core/transaction_pool_test.go | 12 +++++------- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/core/block_processor_test.go b/core/block_processor_test.go index ad29404e1..64add7e8b 100644 --- a/core/block_processor_test.go +++ b/core/block_processor_test.go @@ -4,6 +4,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/pow/ezp" @@ -19,7 +20,7 @@ func proc() (*BlockProcessor, *ChainManager) { func TestNumber(t *testing.T) { bp, chain := proc() - block1 := chain.NewBlock(nil) + block1 := chain.NewBlock(common.Address{}) block1.Header().Number = big.NewInt(3) err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header()) @@ -27,7 +28,7 @@ func TestNumber(t *testing.T) { t.Errorf("expected block number error") } - block1 = chain.NewBlock(nil) + block1 = chain.NewBlock(common.Address{}) err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header()) if err == BlockNumberErr { t.Errorf("didn't expect block number error") diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index 898d37f9c..e49e594a3 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -1,7 +1,6 @@ package core import ( - "bytes" "fmt" "math/big" "os" @@ -35,7 +34,7 @@ func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big // asert the bmans have the same block at i bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash() bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash() - if bytes.Compare(bi1, bi2) != 0 { + if bi1 != bi2 { t.Fatal("chains do not have the same hash at height", i) } @@ -270,11 +269,11 @@ func TestChainInsertions(t *testing.T) { <-done } - if bytes.Equal(chain2[len(chain2)-1].Hash(), chainMan.CurrentBlock().Hash()) { + if chain2[len(chain2)-1].Hash() != chainMan.CurrentBlock().Hash() { t.Error("chain2 is canonical and shouldn't be") } - if !bytes.Equal(chain1[len(chain1)-1].Hash(), chainMan.CurrentBlock().Hash()) { + if chain1[len(chain1)-1].Hash() != chainMan.CurrentBlock().Hash() { t.Error("chain1 isn't canonical and should be") } } @@ -320,7 +319,7 @@ func TestChainMultipleInsertions(t *testing.T) { <-done } - if !bytes.Equal(chains[longest][len(chains[longest])-1].Hash(), chainMan.CurrentBlock().Hash()) { + if chains[longest][len(chains[longest])-1].Hash() != chainMan.CurrentBlock().Hash() { t.Error("Invalid canonical chain") } } diff --git a/core/genesis.go b/core/genesis.go index 70845b502..3e00533ae 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" ) @@ -19,9 +18,6 @@ import ( var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) var ZeroHash512 = make([]byte, 64) -var EmptyShaList = crypto.Sha3(common.Encode([]interface{}{})) -var EmptyListRoot = crypto.Sha3(common.Encode("")) - var GenesisDiff = big.NewInt(131072) var GenesisGasLimit = big.NewInt(3141592) diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 7c50e5e53..f2fe5c748 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -63,7 +63,7 @@ func NewTxPool(eventMux *event.TypeMux) *TxPool { func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { // Validate sender if _, err := tx.From(); err != nil { - return err + return ErrInvalidSender } // Validate curve param v, _, _ := tx.Curve() diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go index 418cb0415..bf9012573 100644 --- a/core/transaction_pool_test.go +++ b/core/transaction_pool_test.go @@ -4,10 +4,10 @@ import ( "crypto/ecdsa" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/state" ) @@ -21,11 +21,11 @@ func SQ() stateQuery { } func (self stateQuery) GetAccount(addr []byte) *state.StateObject { - return state.NewStateObject(addr, self.db) + return state.NewStateObject(common.BytesToAddress(addr), self.db) } func transaction() *types.Transaction { - return types.NewTransactionMessage(make([]byte, 20), common.Big0, common.Big0, common.Big0, nil) + return types.NewTransactionMessage(common.Address{}, common.Big0, common.Big0, common.Big0, nil) } func setup() (*TxPool, *ecdsa.PrivateKey) { @@ -88,10 +88,8 @@ func TestRemoveInvalid(t *testing.T) { func TestInvalidSender(t *testing.T) { pool, _ := setup() - tx := new(types.Transaction) - tx.V = 28 - err := pool.ValidateTransaction(tx) + err := pool.ValidateTransaction(new(types.Transaction)) if err != ErrInvalidSender { - t.Error("expected %v, got %v", ErrInvalidSender, err) + t.Errorf("expected %v, got %v", ErrInvalidSender, err) } } From 064279c0ec2f048cbdd965c095ea332bb8666f94 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Mar 2015 14:04:19 +0100 Subject: [PATCH 36/78] cmd/ethereum, cmd/utils: partial fix for chain import --- cmd/ethereum/admin.go | 5 +---- cmd/utils/cmd.go | 7 +++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cmd/ethereum/admin.go b/cmd/ethereum/admin.go index 967af2553..41aaf46d8 100644 --- a/cmd/ethereum/admin.go +++ b/cmd/ethereum/admin.go @@ -221,13 +221,10 @@ func (js *jsre) exportChain(call otto.FunctionCall) otto.Value { fmt.Println(err) return otto.FalseValue() } - - data := js.ethereum.ChainManager().Export() - if err := common.WriteFile(fn, data); err != nil { + if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil { fmt.Println(err) return otto.FalseValue() } - return otto.TrueValue() } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 66e89abef..feea29d64 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -158,13 +158,12 @@ func ImportChain(chainmgr *core.ChainManager, fn string) error { var i int for ; ; i++ { var b types.Block - err := stream.Decode(&b) - if err == io.EOF { + if err := stream.Decode(&b); err == io.EOF { break } else if err != nil { return fmt.Errorf("at block %d: %v", i, err) } - if err := chainmgr.InsertChain(types.Blocks{b}); err != nil { + if err := chainmgr.InsertChain(types.Blocks{&b}); err != nil { return fmt.Errorf("invalid block %d: %v", i, err) } } @@ -174,7 +173,7 @@ func ImportChain(chainmgr *core.ChainManager, fn string) error { func ExportChain(chainmgr *core.ChainManager, fn string) error { fmt.Printf("exporting blockchain '%s'\n", fn) - fh, err := os.OpenFile(fn, os.O_WRONLY|os.O_TRUNC, os.ModePerm) + fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) if err != nil { return err } From 48dd601de0ffea4e1bf57a8923f2a6126553b575 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Mar 2015 14:15:48 +0100 Subject: [PATCH 37/78] prep template for fixed size hashes --- common/types_template.go | 48 ++++++++++++++++++++++++++++++++++++++++ core/chain_manager.go | 4 ++-- 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 common/types_template.go diff --git a/common/types_template.go b/common/types_template.go new file mode 100644 index 000000000..1c82a36dc --- /dev/null +++ b/common/types_template.go @@ -0,0 +1,48 @@ +// +build none +//sed -e 's/_N_/Hash/g' -e 's/_S_/32/g' -e '1d' types_template.go | gofmt -w hash.go + +package common + +import "math/big" + +type _N_ [_S_]byte + +func BytesTo_N_(b []byte) _N_ { + var h _N_ + h.SetBytes(b) + return h +} +func StringTo_N_(s string) _N_ { return BytesTo_N_([]byte(s)) } +func BigTo_N_(b *big.Int) _N_ { return BytesTo_N_(b.Bytes()) } +func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) } + +// Don't use the default 'String' method in case we want to overwrite + +// Get the string representation of the underlying hash +func (h _N_) Str() string { return string(h[:]) } +func (h _N_) Bytes() []byte { return h[:] } +func (h _N_) Big() *big.Int { return Bytes2Big(h[:]) } +func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) } + +// Sets the hash to the value of b. If b is larger than len(h) it will panic +func (h *_N_) SetBytes(b []byte) { + // Use the right most bytes + if len(b) > len(h) { + b = b[len(b)-_S_:] + } + + // Reverse the loop + for i := len(b) - 1; i >= 0; i-- { + h[_S_-len(b)+i] = b[i] + } +} + +// Set string `s` to h. If s is larger than len(h) it will panic +func (h *_N_) SetString(s string) { h.SetBytes([]byte(s)) } + +// Sets h to other +func (h *_N_) Set(other _N_) { + for i, v := range other { + h[i] = v + } +} diff --git a/core/chain_manager.go b/core/chain_manager.go index 5316a3423..0251f7c72 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -37,8 +37,8 @@ func CalcDifficulty(block, parent *types.Header) *big.Int { diff.Sub(parent.Difficulty, adjust) } - if diff.Cmp(GenesisDiff) < 0 { - return GenesisDiff + if diff.Cmp(min) < 0 { + return min } return diff From 965c9babe336cfa8d5c740d5356acbc5f9ba4a72 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Mar 2015 12:15:43 +0100 Subject: [PATCH 38/78] rlp: fix encoding of one element strings and byte slices The encoder was missing a special case for one element strings whose element is below 0x7f. Such strings must be encoded as a single byte without a string header. --- rlp/encode.go | 21 ++++++++++++++------- rlp/encode_test.go | 6 ++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/rlp/encode.go b/rlp/encode.go index 42bbb876c..7ac74d8fb 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -203,8 +203,13 @@ func (w *encbuf) encodeStringHeader(size int) { } func (w *encbuf) encodeString(b []byte) { - w.encodeStringHeader(len(b)) - w.str = append(w.str, b...) + if len(b) == 1 && b[0] <= 0x7F { + // fits single byte, no string header + w.str = append(w.str, b[0]) + } else { + w.encodeStringHeader(len(b)) + w.str = append(w.str, b...) + } } func (w *encbuf) list() *listhead { @@ -404,9 +409,6 @@ func writeBigInt(i *big.Int, w *encbuf) error { return fmt.Errorf("rlp: cannot encode negative *big.Int") } else if cmp == 0 { w.str = append(w.str, 0x80) - } else if bits := i.BitLen(); bits < 8 { - // fits single byte - w.str = append(w.str, byte(i.Uint64())) } else { w.encodeString(i.Bytes()) } @@ -434,8 +436,13 @@ func writeByteArray(val reflect.Value, w *encbuf) error { func writeString(val reflect.Value, w *encbuf) error { s := val.String() - w.encodeStringHeader(len(s)) - w.str = append(w.str, s...) + if len(s) == 1 && s[0] <= 0x7f { + // fits single byte, no string header + w.str = append(w.str, s[0]) + } else { + w.encodeStringHeader(len(s)) + w.str = append(w.str, s...) + } return nil } diff --git a/rlp/encode_test.go b/rlp/encode_test.go index 852cb6f59..611514bda 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -103,12 +103,18 @@ var encTests = []encTest{ // byte slices, strings {val: []byte{}, output: "80"}, + {val: []byte{0x7E}, output: "7E"}, + {val: []byte{0x7F}, output: "7F"}, + {val: []byte{0x80}, output: "8180"}, {val: []byte{1, 2, 3}, output: "83010203"}, {val: []namedByteType{1, 2, 3}, output: "83010203"}, {val: [...]namedByteType{1, 2, 3}, output: "83010203"}, {val: "", output: "80"}, + {val: "\x7E", output: "7E"}, + {val: "\x7F", output: "7F"}, + {val: "\x80", output: "8180"}, {val: "dog", output: "83646F67"}, { val: "Lorem ipsum dolor sit amet, consectetur adipisicing eli", From ad7e4912146d0bfe9907a11d5e302db3143e156e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Mar 2015 15:04:29 +0100 Subject: [PATCH 39/78] improved test output --- cmd/ethtest/main.go | 69 +++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go index cf1ec6dfa..ee6bcc540 100644 --- a/cmd/ethtest/main.go +++ b/cmd/ethtest/main.go @@ -24,6 +24,7 @@ package main import ( "bytes" "encoding/json" + "fmt" "io" "io/ioutil" "log" @@ -33,6 +34,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" @@ -66,7 +68,7 @@ type Account struct { } func StateObjectFromAccount(db common.Database, addr string, account Account) *state.StateObject { - obj := state.NewStateObject(common.Hex2Bytes(addr), db) + obj := state.NewStateObject(common.HexToAddress(addr), db) obj.SetBalance(common.Big(account.Balance)) if common.IsHex(account.Code) { @@ -112,7 +114,7 @@ func RunVmTest(r io.Reader) (failed int) { for name, test := range tests { db, _ := ethdb.NewMemDatabase() - statedb := state.New(nil, db) + statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) @@ -135,63 +137,82 @@ func RunVmTest(r io.Reader) (failed int) { rexp := helper.FromHex(test.Out) if bytes.Compare(rexp, ret) != 0 { - helper.Log.Infof("FAIL: %s's return failed. Expected %x, got %x\n", name, rexp, ret) + helper.Log.Infof("%s's return failed. Expected %x, got %x\n", name, rexp, ret) failed = 1 } for addr, account := range test.Post { - obj := statedb.GetStateObject(helper.FromHex(addr)) + obj := statedb.GetStateObject(common.HexToAddress(addr)) if obj == nil { continue } if len(test.Exec) == 0 { if obj.Balance().Cmp(common.Big(account.Balance)) != 0 { - helper.Log.Infof("FAIL: %s's : (%x) balance failed. Expected %v, got %v => %v\n", - name, - obj.Address()[:4], - account.Balance, - obj.Balance(), - new(big.Int).Sub(common.Big(account.Balance), obj.Balance()), - ) + helper.Log.Infof("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) failed = 1 } } for addr, value := range account.Storage { - v := obj.GetState(helper.FromHex(addr)).Bytes() + v := obj.GetState(common.HexToHash(addr)).Bytes() vexp := helper.FromHex(value) if bytes.Compare(v, vexp) != 0 { - helper.Log.Infof("FAIL: %s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) + helper.Log.Infof("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) failed = 1 } } } - if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { - helper.Log.Infof("FAIL: %s's : Post state root error. Expected %s, got %x\n", name, test.PostStateRoot, statedb.Root()) + statedb.Sync() + //if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { + if common.HexToHash(test.PostStateRoot) != statedb.Root() { + helper.Log.Infof("%s's : Post state root failed. Expected %s, got %x", name, test.PostStateRoot, statedb.Root()) failed = 1 } if len(test.Logs) > 0 { if len(test.Logs) != len(logs) { - helper.Log.Infof("FAIL: log length mismatch. Expected %d, got %d", len(test.Logs), len(logs)) + helper.Log.Infof("log length failed. Expected %d, got %d", len(test.Logs), len(logs)) failed = 1 } else { - /* - fmt.Println("A", test.Logs) - fmt.Println("B", logs) - for i, log := range test.Logs { - genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) - if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { - t.Errorf("bloom mismatch") + for i, log := range test.Logs { + if common.HexToAddress(log.AddressF) != logs[i].Address() { + helper.Log.Infof("'%s' log address failed. Expected %v got %x", name, log.AddressF, logs[i].Address()) + failed = 1 + } + + if !bytes.Equal(logs[i].Data(), helper.FromHex(log.DataF)) { + helper.Log.Infof("'%s' log data failed. Expected %v got %x", name, log.DataF, logs[i].Data()) + failed = 1 + } + + if len(log.TopicsF) != len(logs[i].Topics()) { + helper.Log.Infof("'%s' log topics length failed. Expected %d got %d", name, len(log.TopicsF), logs[i].Topics()) + failed = 1 + } else { + for j, topic := range log.TopicsF { + if common.HexToHash(topic) != logs[i].Topics()[j] { + helper.Log.Infof("'%s' log topic[%d] failed. Expected %v got %x", name, j, topic, logs[i].Topics()[j]) + failed = 1 } } - */ + } + genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) + + if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { + helper.Log.Infof("'%s' bloom failed.", name) + failed = 1 + } + } } } + if failed == 1 { + fmt.Println(string(statedb.Dump())) + } + logger.Flush() } From 4811f460e7aad37c6c6867df0461a5fa162b5f2c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Mar 2015 15:08:04 +0100 Subject: [PATCH 40/78] p2p: export ExpectMsg (for eth protocol testing) --- p2p/message.go | 32 ++++++++++++++++++++++++++++++++ p2p/peer_test.go | 32 -------------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/p2p/message.go b/p2p/message.go index 14e4404c9..e7e6af287 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -208,3 +208,35 @@ func (p *MsgPipeRW) Close() error { close(p.closing) return nil } + +// ExpectMsg reads a message from r and verifies that its +// code and encoded RLP content match the provided values. +// If content is nil, the payload is discarded and not verified. +func ExpectMsg(r MsgReader, code uint64, content interface{}) error { + msg, err := r.ReadMsg() + if err != nil { + return err + } + if msg.Code != code { + return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) + } + if content == nil { + return msg.Discard() + } else { + contentEnc, err := rlp.EncodeToBytes(content) + if err != nil { + panic("content encode error: " + err.Error()) + } + if int(msg.Size) != len(contentEnc) { + return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) + } + actualContent, err := ioutil.ReadAll(msg.Payload) + if err != nil { + return err + } + if !bytes.Equal(actualContent, contentEnc) { + return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) + } + } + return nil +} diff --git a/p2p/peer_test.go b/p2p/peer_test.go index cc9f1f0cd..626dfd00f 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -192,35 +192,3 @@ func TestNewPeer(t *testing.T) { p.Disconnect(DiscAlreadyConnected) // Should not hang } - -// expectMsg reads a message from r and verifies that its -// code and encoded RLP content match the provided values. -// If content is nil, the payload is discarded and not verified. -func expectMsg(r MsgReader, code uint64, content interface{}) error { - msg, err := r.ReadMsg() - if err != nil { - return err - } - if msg.Code != code { - return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) - } - if content == nil { - return msg.Discard() - } else { - contentEnc, err := rlp.EncodeToBytes(content) - if err != nil { - panic("content encode error: " + err.Error()) - } - if int(msg.Size) != len(contentEnc) { - return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) - } - actualContent, err := ioutil.ReadAll(msg.Payload) - if err != nil { - return err - } - if !bytes.Equal(actualContent, contentEnc) { - return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) - } - } - return nil -} From 5ba51594c7eb1f04b3636e6413de6d4eb70228d2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Mar 2015 15:11:02 +0100 Subject: [PATCH 41/78] p2p: use package rlp to encode messages Message encoding functions have been renamed to catch any uses. The switch to the new encoder can cause subtle incompatibilities. If there are any users outside of our tree, they will at least be alerted that there was a change. NewMsg no longer exists. The replacements for EncodeMsg are called Send and SendItems. --- p2p/handshake.go | 8 ++------ p2p/message.go | 36 +++++++++++++++++++++++------------- p2p/message_test.go | 24 ++++-------------------- p2p/peer.go | 6 +++--- p2p/peer_test.go | 41 +++++++++++++++++++++-------------------- p2p/rlpx_test.go | 4 ++-- p2p/server.go | 11 ++++++++--- p2p/server_test.go | 2 +- 8 files changed, 64 insertions(+), 68 deletions(-) diff --git a/p2p/handshake.go b/p2p/handshake.go index 7fc497517..031064407 100644 --- a/p2p/handshake.go +++ b/p2p/handshake.go @@ -92,7 +92,7 @@ func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake) ( return nil, errors.New("node ID in protocol handshake does not match encryption handshake") } // TODO: validate that handshake node ID matches - if err := writeProtocolHandshake(rw, our); err != nil { + if err := Send(rw, handshakeMsg, our); err != nil { return nil, fmt.Errorf("protocol write error: %v", err) } return &conn{rw, rhs}, nil @@ -106,7 +106,7 @@ func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, // Run the protocol handshake using authenticated messages. rw := newRlpxFrameRW(fd, secrets) - if err := writeProtocolHandshake(rw, our); err != nil { + if err := Send(rw, handshakeMsg, our); err != nil { return nil, fmt.Errorf("protocol write error: %v", err) } rhs, err := readProtocolHandshake(rw, our) @@ -398,10 +398,6 @@ func xor(one, other []byte) (xor []byte) { return xor } -func writeProtocolHandshake(w MsgWriter, our *protoHandshake) error { - return EncodeMsg(w, handshakeMsg, our.Version, our.Name, our.Caps, our.ListenPort, our.ID[:]) -} - func readProtocolHandshake(r MsgReader, our *protoHandshake) (*protoHandshake, error) { // read and handle remote handshake msg, err := r.ReadMsg() diff --git a/p2p/message.go b/p2p/message.go index e7e6af287..5dc7d5460 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -11,7 +11,6 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" ) @@ -28,13 +27,7 @@ type Msg struct { Payload io.Reader } -// NewMsg creates an RLP-encoded message with the given code. -func NewMsg(code uint64, params ...interface{}) Msg { - p := bytes.NewReader(common.Encode(params)) - return Msg{Code: code, Size: uint32(p.Len()), Payload: p} -} - -// Decode parse the RLP content of a message into +// Decode parses the RLP content of a message into // the given value, which must be a pointer. // // For the decoding rules, please see package rlp. @@ -76,13 +69,30 @@ type MsgReadWriter interface { MsgWriter } -// EncodeMsg writes an RLP-encoded message with the given code and -// data elements. -func EncodeMsg(w MsgWriter, code uint64, data ...interface{}) error { - return w.WriteMsg(NewMsg(code, data...)) +// Send writes an RLP-encoded message with the given code. +// data should encode as an RLP list. +func Send(w MsgWriter, msgcode uint64, data interface{}) error { + size, r, err := rlp.EncodeToReader(data) + if err != nil { + return err + } + return w.WriteMsg(Msg{Code: msgcode, Size: uint32(size), Payload: r}) } -// netWrapper wrapsa MsgReadWriter with locks around +// SendItems writes an RLP with the given code and data elements. +// For a call such as: +// +// SendItems(w, code, e1, e2, e3) +// +// the message payload will be an RLP list containing the items: +// +// [e1, e2, e3] +// +func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { + return Send(w, msgcode, elems) +} + +// netWrapper wraps a MsgReadWriter with locks around // ReadMsg/WriteMsg and applies read/write deadlines. type netWrapper struct { rmu, wmu sync.Mutex diff --git a/p2p/message_test.go b/p2p/message_test.go index 31ed61d87..9a93dd347 100644 --- a/p2p/message_test.go +++ b/p2p/message_test.go @@ -5,33 +5,17 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "runtime" "strings" "testing" "time" ) -func TestNewMsg(t *testing.T) { - msg := NewMsg(3, 1, "000") - if msg.Code != 3 { - t.Errorf("incorrect code %d, want %d", msg.Code) - } - expect := unhex("c50183303030") - if msg.Size != uint32(len(expect)) { - t.Errorf("incorrect size %d, want %d", msg.Size, len(expect)) - } - pl, _ := ioutil.ReadAll(msg.Payload) - if !bytes.Equal(pl, expect) { - t.Errorf("incorrect payload content, got %x, want %x", pl, expect) - } -} - func ExampleMsgPipe() { rw1, rw2 := MsgPipe() go func() { - EncodeMsg(rw1, 8, []byte{0, 0}) - EncodeMsg(rw1, 5, []byte{1, 1}) + Send(rw1, 8, [][]byte{{0, 0}}) + Send(rw1, 5, [][]byte{{1, 1}}) rw1.Close() }() @@ -40,7 +24,7 @@ func ExampleMsgPipe() { if err != nil { break } - var data [1][]byte + var data [][]byte msg.Decode(&data) fmt.Printf("msg: %d, %x\n", msg.Code, data[0]) } @@ -55,7 +39,7 @@ loop: rw1, rw2 := MsgPipe() done := make(chan struct{}) go func() { - if err := EncodeMsg(rw1, 1); err == nil { + if err := SendItems(rw1, 1); err == nil { t.Error("EncodeMsg returned nil error") } else if err != ErrPipeClosed { t.Error("EncodeMsg returned wrong error: got %v, want %v", err, ErrPipeClosed) diff --git a/p2p/peer.go b/p2p/peer.go index c2c83abfc..ee5199d78 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -132,7 +132,7 @@ loop: select { case <-ping.C: go func() { - if err := EncodeMsg(p.rw, pingMsg, nil); err != nil { + if err := SendItems(p.rw, pingMsg); err != nil { p.protoErr <- err return } @@ -161,7 +161,7 @@ loop: func (p *Peer) politeDisconnect(reason DiscReason) { done := make(chan struct{}) go func() { - EncodeMsg(p.rw, discMsg, uint(reason)) + SendItems(p.rw, discMsg, uint(reason)) // Wait for the other side to close the connection. // Discard any data that they send until then. io.Copy(ioutil.Discard, p.conn) @@ -192,7 +192,7 @@ func (p *Peer) handle(msg Msg) error { switch { case msg.Code == pingMsg: msg.Discard() - go EncodeMsg(p.rw, pongMsg) + go SendItems(p.rw, pongMsg) case msg.Code == discMsg: var reason [1]DiscReason // no need to discard or for error checking, we'll close the diff --git a/p2p/peer_test.go b/p2p/peer_test.go index 626dfd00f..3c4c71c0c 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -4,13 +4,10 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net" "reflect" "testing" "time" - - "github.com/ethereum/go-ethereum/rlp" ) var discard = Protocol{ @@ -55,13 +52,13 @@ func TestPeerProtoReadMsg(t *testing.T) { Name: "a", Length: 5, Run: func(peer *Peer, rw MsgReadWriter) error { - if err := expectMsg(rw, 2, []uint{1}); err != nil { + if err := ExpectMsg(rw, 2, []uint{1}); err != nil { t.Error(err) } - if err := expectMsg(rw, 3, []uint{2}); err != nil { + if err := ExpectMsg(rw, 3, []uint{2}); err != nil { t.Error(err) } - if err := expectMsg(rw, 4, []uint{3}); err != nil { + if err := ExpectMsg(rw, 4, []uint{3}); err != nil { t.Error(err) } close(done) @@ -72,9 +69,9 @@ func TestPeerProtoReadMsg(t *testing.T) { closer, rw, _, errc := testPeer([]Protocol{proto}) defer closer.Close() - EncodeMsg(rw, baseProtocolLength+2, 1) - EncodeMsg(rw, baseProtocolLength+3, 2) - EncodeMsg(rw, baseProtocolLength+4, 3) + Send(rw, baseProtocolLength+2, []uint{1}) + Send(rw, baseProtocolLength+3, []uint{2}) + Send(rw, baseProtocolLength+4, []uint{3}) select { case <-done: @@ -92,10 +89,10 @@ func TestPeerProtoEncodeMsg(t *testing.T) { Name: "a", Length: 2, Run: func(peer *Peer, rw MsgReadWriter) error { - if err := EncodeMsg(rw, 2); err == nil { + if err := SendItems(rw, 2); err == nil { t.Error("expected error for out-of-range msg code, got nil") } - if err := EncodeMsg(rw, 1, "foo", "bar"); err != nil { + if err := SendItems(rw, 1, "foo", "bar"); err != nil { t.Errorf("write error: %v", err) } return nil @@ -104,7 +101,7 @@ func TestPeerProtoEncodeMsg(t *testing.T) { closer, rw, _, _ := testPeer([]Protocol{proto}) defer closer.Close() - if err := expectMsg(rw, 17, []string{"foo", "bar"}); err != nil { + if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { t.Error(err) } } @@ -115,11 +112,15 @@ func TestPeerWriteForBroadcast(t *testing.T) { closer, rw, peer, peerErr := testPeer([]Protocol{discard}) defer closer.Close() + emptymsg := func(code uint64) Msg { + return Msg{Code: code, Size: 0, Payload: bytes.NewReader(nil)} + } + // test write errors - if err := peer.writeProtoMsg("b", NewMsg(3)); err == nil { + if err := peer.writeProtoMsg("b", emptymsg(3)); err == nil { t.Errorf("expected error for unknown protocol, got nil") } - if err := peer.writeProtoMsg("discard", NewMsg(8)); err == nil { + if err := peer.writeProtoMsg("discard", emptymsg(8)); err == nil { t.Errorf("expected error for out-of-range msg code, got nil") } else if perr, ok := err.(*peerError); !ok || perr.Code != errInvalidMsgCode { t.Errorf("wrong error for out-of-range msg code, got %#v", err) @@ -128,14 +129,14 @@ func TestPeerWriteForBroadcast(t *testing.T) { // setup for reading the message on the other end read := make(chan struct{}) go func() { - if err := expectMsg(rw, 16, nil); err != nil { + if err := ExpectMsg(rw, 16, nil); err != nil { t.Error(err) } close(read) }() // test successful write - if err := peer.writeProtoMsg("discard", NewMsg(0)); err != nil { + if err := peer.writeProtoMsg("discard", emptymsg(0)); err != nil { t.Errorf("expect no error for known protocol: %v", err) } select { @@ -150,10 +151,10 @@ func TestPeerPing(t *testing.T) { closer, rw, _, _ := testPeer(nil) defer closer.Close() - if err := EncodeMsg(rw, pingMsg); err != nil { + if err := SendItems(rw, pingMsg); err != nil { t.Fatal(err) } - if err := expectMsg(rw, pongMsg, nil); err != nil { + if err := ExpectMsg(rw, pongMsg, nil); err != nil { t.Error(err) } } @@ -163,10 +164,10 @@ func TestPeerDisconnect(t *testing.T) { closer, rw, _, disc := testPeer(nil) defer closer.Close() - if err := EncodeMsg(rw, discMsg, DiscQuitting); err != nil { + if err := SendItems(rw, discMsg, DiscQuitting); err != nil { t.Fatal(err) } - if err := expectMsg(rw, discMsg, []interface{}{DiscRequested}); err != nil { + if err := ExpectMsg(rw, discMsg, []interface{}{DiscRequested}); err != nil { t.Error(err) } closer.Close() // make test end faster diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go index 49354c7ed..d98f1c2cd 100644 --- a/p2p/rlpx_test.go +++ b/p2p/rlpx_test.go @@ -30,7 +30,7 @@ ba628a4ba590cb43f7848f41c4382885 `) // Check WriteMsg. This puts a message into the buffer. - if err := EncodeMsg(rw, 8, 1, 2, 3, 4); err != nil { + if err := Send(rw, 8, []uint{1, 2, 3, 4}); err != nil { t.Fatalf("WriteMsg error: %v", err) } written := buf.Bytes() @@ -102,7 +102,7 @@ func TestRlpxFrameRW(t *testing.T) { for i := 0; i < 10; i++ { // write message into conn buffer wmsg := []interface{}{"foo", "bar", strings.Repeat("test", i)} - err := EncodeMsg(rw1, uint64(i), wmsg...) + err := Send(rw1, uint64(i), wmsg) if err != nil { t.Fatalf("WriteMsg error (i=%d): %v", i, err) } diff --git a/p2p/server.go b/p2p/server.go index 9c148ba39..813b0676f 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -9,10 +9,10 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/rlp" ) const ( @@ -129,10 +129,14 @@ func (srv *Server) SuggestPeer(n *discover.Node) { // Broadcast sends an RLP-encoded message to all connected peers. // This method is deprecated and will be removed later. -func (srv *Server) Broadcast(protocol string, code uint64, data ...interface{}) { +func (srv *Server) Broadcast(protocol string, code uint64, data interface{}) error { var payload []byte if data != nil { - payload = common.Encode(data) + var err error + payload, err = rlp.EncodeToBytes(data) + if err != nil { + return err + } } srv.lock.RLock() defer srv.lock.RUnlock() @@ -146,6 +150,7 @@ func (srv *Server) Broadcast(protocol string, code uint64, data ...interface{}) peer.writeProtoMsg(protocol, msg) } } + return nil } // Start starts running the server. diff --git a/p2p/server_test.go b/p2p/server_test.go index 30447050c..14e7c7de2 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -149,7 +149,7 @@ func TestServerBroadcast(t *testing.T) { connected.Wait() // broadcast one message - srv.Broadcast("discard", 0, "foo") + srv.Broadcast("discard", 0, []string{"foo"}) golden := unhex("66e94d166f0a2c3b884cfa59ca34") // check that the message has been written everywhere From a7bced779a599fb3f87a69a5f8bb8017b62dc0a3 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Mar 2015 15:15:07 +0100 Subject: [PATCH 42/78] p2p: log disconnect requests This helps a lot with debugging. --- p2p/peer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p/peer.go b/p2p/peer.go index ee5199d78..6b97ea58d 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -198,6 +198,7 @@ func (p *Peer) handle(msg Msg) error { // no need to discard or for error checking, we'll close the // connection after this. rlp.Decode(msg.Payload, &reason) + p.Debugf("Disconnect requested: %v\n", reason[0]) p.Disconnect(DiscRequested) return discRequestedError(reason[0]) case msg.Code < baseProtocolLength: From b9e0b11e7da387bbb426d25c36d495c4f099722f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Mar 2015 15:16:06 +0100 Subject: [PATCH 43/78] p2p: interrupt MsgPipe payload read/write This is better because protocols might not actually read the payload for some errors (msg too big, etc.) which can be a pain to test with the old behaviour. --- p2p/message.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/p2p/message.go b/p2p/message.go index 5dc7d5460..ef3630a90 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -185,7 +185,10 @@ func (p *MsgPipeRW) WriteMsg(msg Msg) error { case p.w <- msg: if msg.Size > 0 { // wait for payload read or discard - <-consumed + select { + case <-consumed: + case <-p.closing: + } } return nil case <-p.closing: @@ -207,8 +210,8 @@ func (p *MsgPipeRW) ReadMsg() (Msg, error) { } // Close unblocks any pending ReadMsg and WriteMsg calls on both ends -// of the pipe. They will return ErrPipeClosed. Note that Close does -// not interrupt any reads from a message payload. +// of the pipe. They will return ErrPipeClosed. Close also +// interrupts any reads from a message payload. func (p *MsgPipeRW) Close() error { if atomic.AddInt32(p.closed, 1) != 1 { // someone else is already closing From e80dda605130479086bed363e395a102a89a574a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Mar 2015 15:18:31 +0100 Subject: [PATCH 44/78] eth, whisper: adapt for RLP encoder switch in package p2p I have rewritten the protocol test to use p2p.MsgPipe because p2p.NewMsg is gone. --- eth/backend.go | 4 +- eth/protocol.go | 95 ++++++++++------------ eth/protocol_test.go | 189 +++++++++++++++++-------------------------- whisper/envelope.go | 2 +- whisper/peer.go | 9 +-- 5 files changed, 124 insertions(+), 175 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 9e5324688..afe314d74 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -405,7 +405,7 @@ func (self *Ethereum) txBroadcastLoop() { // automatically stops if unsubscribe for obj := range self.txSub.Chan() { event := obj.(core.TxPreEvent) - self.net.Broadcast("eth", TxMsg, event.Tx.RlpData()) + self.net.Broadcast("eth", TxMsg, []*types.Transaction{event.Tx}) } } @@ -414,7 +414,7 @@ func (self *Ethereum) blockBroadcastLoop() { for obj := range self.blockSub.Chan() { switch ev := obj.(type) { case core.NewMinedBlockEvent: - self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td) + self.net.Broadcast("eth", NewBlockMsg, []interface{}{ev.Block, ev.Block.Td}) } } } diff --git a/eth/protocol.go b/eth/protocol.go index a1c2ae688..6d610a663 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -89,7 +89,7 @@ type blockPool interface { RemovePeer(peerId string) } -// message structs used for rlp decoding +// message structs used for RLP serialization type newBlockMsgData struct { Block *types.Block TD *big.Int @@ -100,6 +100,14 @@ type getBlockHashesMsgData struct { Amount uint64 } +type statusMsgData struct { + ProtocolVersion uint32 + NetworkId uint32 + TD *big.Int + CurrentBlock common.Hash + GenesisBlock common.Hash +} + // main entrypoint, wrappers starting a server running the eth protocol // use this constructor to attach the protocol ("class") to server caps // the Dev p2p layer then runs the protocol instance on each peer @@ -132,18 +140,25 @@ func runEthProtocol(protocolVersion, networkId int, txPool txPool, chainManager }, id: fmt.Sprintf("%x", id[:8]), } - err = self.handleStatus() - if err == nil { - self.propagateTxs() - for { - err = self.handle() - if err != nil { - self.blockPool.RemovePeer(self.id) - break - } + + // handshake. + if err := self.handleStatus(); err != nil { + return err + } + defer self.blockPool.RemovePeer(self.id) + + // propagate existing transactions. new transactions appearing + // after this will be sent via broadcasts. + if err := p2p.Send(rw, TxMsg, txPool.GetTransactions()); err != nil { + return err + } + + // main loop. handle incoming messages. + for { + if err := self.handle(); err != nil { + return err } } - return } func (self *ethProtocol) handle() error { @@ -186,7 +201,7 @@ func (self *ethProtocol) handle() error { request.Amount = maxHashes } hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount) - return p2p.EncodeMsg(self.rw, BlockHashesMsg, rlp.Flat(hashes)) + return p2p.Send(self.rw, BlockHashesMsg, hashes) case BlockHashesMsg: msgStream := rlp.NewStream(msg.Payload) @@ -216,7 +231,7 @@ func (self *ethProtocol) handle() error { return err } - var blocks []interface{} + var blocks []*types.Block var i int for { i++ @@ -224,7 +239,7 @@ func (self *ethProtocol) handle() error { err := msgStream.Decode(&hash) if err == rlp.EOL { break - } else { + } else if err != nil { return self.protoError(ErrDecode, "msg %v: %v", msg, err) } @@ -236,7 +251,7 @@ func (self *ethProtocol) handle() error { break } } - return p2p.EncodeMsg(self.rw, BlocksMsg, blocks...) + return p2p.Send(self.rw, BlocksMsg, blocks) case BlocksMsg: msgStream := rlp.NewStream(msg.Payload) @@ -283,29 +298,8 @@ func (self *ethProtocol) handle() error { return nil } -type statusMsgData struct { - ProtocolVersion uint32 - NetworkId uint32 - TD *big.Int - CurrentBlock common.Hash - GenesisBlock common.Hash -} - -func (self *ethProtocol) statusMsg() p2p.Msg { - td, currentBlock, genesisBlock := self.chainManager.Status() - - return p2p.NewMsg(StatusMsg, - uint32(self.protocolVersion), - uint32(self.networkId), - td, - currentBlock, - genesisBlock, - ) -} - func (self *ethProtocol) handleStatus() error { - // send precanned status message - if err := self.rw.WriteMsg(self.statusMsg()); err != nil { + if err := self.sendStatus(); err != nil { return err } @@ -314,11 +308,9 @@ func (self *ethProtocol) handleStatus() error { if err != nil { return err } - if msg.Code != StatusMsg { return self.protoError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) } - if msg.Size > ProtocolMaxMsgSize { return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) } @@ -351,12 +343,12 @@ func (self *ethProtocol) handleStatus() error { func (self *ethProtocol) requestBlockHashes(from common.Hash) error { self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4]) - return p2p.EncodeMsg(self.rw, GetBlockHashesMsg, interface{}(from), uint64(maxHashes)) + return p2p.Send(self.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, maxHashes}) } func (self *ethProtocol) requestBlocks(hashes []common.Hash) error { self.peer.Debugf("fetching %v blocks", len(hashes)) - return p2p.EncodeMsg(self.rw, GetBlocksMsg, rlp.Flat(hashes)) + return p2p.Send(self.rw, GetBlocksMsg, hashes) } func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) { @@ -365,19 +357,20 @@ func (self *ethProtocol) protoError(code int, format string, params ...interface return } +func (self *ethProtocol) sendStatus() error { + td, currentBlock, genesisBlock := self.chainManager.Status() + return p2p.Send(self.rw, StatusMsg, &statusMsgData{ + ProtocolVersion: uint32(self.protocolVersion), + NetworkId: uint32(self.networkId), + TD: td, + CurrentBlock: currentBlock, + GenesisBlock: genesisBlock, + }) +} + func (self *ethProtocol) protoErrorDisconnect(err *errs.Error) { err.Log(self.peer.Logger) if err.Fatal() { self.peer.Disconnect(p2p.DiscSubprotocolError) } } - -func (self *ethProtocol) propagateTxs() { - transactions := self.txPool.GetTransactions() - iface := make([]interface{}, len(transactions)) - for i, transaction := range transactions { - iface[i] = transaction - } - - self.rw.WriteMsg(p2p.NewMsg(TxMsg, iface...)) -} diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 108fb4475..7620b3854 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -1,8 +1,6 @@ package eth import ( - "bytes" - "io" "log" "math/big" "os" @@ -29,52 +27,21 @@ func logInit() { } } -type testMsgReadWriter struct { - in chan p2p.Msg - out []p2p.Msg -} - -func (self *testMsgReadWriter) In(msg p2p.Msg) { - self.in <- msg -} - -func (self *testMsgReadWriter) Out() (msg p2p.Msg, ok bool) { - if len(self.out) > 0 { - msg = self.out[0] - self.out = self.out[1:] - ok = true - } - return -} - -func (self *testMsgReadWriter) WriteMsg(msg p2p.Msg) error { - self.out = append(self.out, msg) - return nil -} - -func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) { - msg, ok := <-self.in - if !ok { - return msg, io.EOF - } - return msg, nil -} - type testTxPool struct { getTransactions func() []*types.Transaction addTransactions func(txs []*types.Transaction) } type testChainManager struct { - getBlockHashes func(hash []byte, amount uint64) (hashes [][]byte) - getBlock func(hash []byte) *types.Block - status func() (td *big.Int, currentBlock []byte, genesisBlock []byte) + getBlockHashes func(hash common.Hash, amount uint64) (hashes []common.Hash) + getBlock func(hash common.Hash) *types.Block + status func() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) } type testBlockPool struct { - addBlockHashes func(next func() ([]byte, bool), peerId string) + addBlockHashes func(next func() (common.Hash, bool), peerId string) addBlock func(block *types.Block, peerId string) (err error) - addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool) + addPeer func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) removePeer func(peerId string) } @@ -93,28 +60,28 @@ func (self *testTxPool) AddTransactions(txs []*types.Transaction) { func (self *testTxPool) GetTransactions() types.Transactions { return nil } -func (self *testChainManager) GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) { +func (self *testChainManager) GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash) { if self.getBlockHashes != nil { hashes = self.getBlockHashes(hash, amount) } return } -func (self *testChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { +func (self *testChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { if self.status != nil { td, currentBlock, genesisBlock = self.status() } return } -func (self *testChainManager) GetBlock(hash []byte) (block *types.Block) { +func (self *testChainManager) GetBlock(hash common.Hash) (block *types.Block) { if self.getBlock != nil { block = self.getBlock(hash) } return } -func (self *testBlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) { +func (self *testBlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId string) { if self.addBlockHashes != nil { self.addBlockHashes(next, peerId) } @@ -126,7 +93,7 @@ func (self *testBlockPool) AddBlock(block *types.Block, peerId string) { } } -func (self *testBlockPool) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool) { +func (self *testBlockPool) AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestBlockHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) { if self.addPeer != nil { best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError) } @@ -147,28 +114,36 @@ func testPeer() *p2p.Peer { } type ethProtocolTester struct { + p2p.MsgReadWriter // writing to the tester feeds the protocol + quit chan error - rw *testMsgReadWriter // p2p.MsgReadWriter - txPool *testTxPool // txPool - chainManager *testChainManager // chainManager - blockPool *testBlockPool // blockPool + pipe *p2p.MsgPipeRW // the protocol read/writes on this end + txPool *testTxPool // txPool + chainManager *testChainManager // chainManager + blockPool *testBlockPool // blockPool t *testing.T } func newEth(t *testing.T) *ethProtocolTester { + p1, p2 := p2p.MsgPipe() return ðProtocolTester{ - quit: make(chan error), - rw: &testMsgReadWriter{in: make(chan p2p.Msg, 10)}, - txPool: &testTxPool{}, - chainManager: &testChainManager{}, - blockPool: &testBlockPool{}, - t: t, + MsgReadWriter: p1, + quit: make(chan error, 1), + pipe: p2, + txPool: &testTxPool{}, + chainManager: &testChainManager{}, + blockPool: &testBlockPool{}, + t: t, } } func (self *ethProtocolTester) reset() { - self.rw = &testMsgReadWriter{in: make(chan p2p.Msg, 10)} - self.quit = make(chan error) + self.pipe.Close() + + p1, p2 := p2p.MsgPipe() + self.MsgReadWriter = p1 + self.pipe = p2 + self.quit = make(chan error, 1) } func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err error) { @@ -190,33 +165,8 @@ func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err return } -func (self *ethProtocolTester) In(msg p2p.Msg) { - self.rw.In(msg) -} - -func (self *ethProtocolTester) Out() (p2p.Msg, bool) { - return self.rw.Out() -} - -func (self *ethProtocolTester) checkMsg(i int, code uint64, val interface{}) (msg p2p.Msg) { - if i >= len(self.rw.out) { - self.t.Errorf("expected at least %v msgs, got %v", i, len(self.rw.out)) - return - } - msg = self.rw.out[i] - if msg.Code != code { - self.t.Errorf("expected msg code %v, got %v", code, msg.Code) - } - if val != nil { - if err := msg.Decode(val); err != nil { - self.t.Errorf("rlp encoding error: %v", err) - } - } - return -} - func (self *ethProtocolTester) run() { - err := runEthProtocol(ProtocolVersion, NetworkId, self.txPool, self.chainManager, self.blockPool, testPeer(), self.rw) + err := runEthProtocol(ProtocolVersion, NetworkId, self.txPool, self.chainManager, self.blockPool, testPeer(), self.pipe) self.quit <- err } @@ -224,41 +174,52 @@ func TestStatusMsgErrors(t *testing.T) { logInit() eth := newEth(t) td := common.Big1 - currentBlock := []byte{1} - genesis := []byte{2} - eth.chainManager.status = func() (*big.Int, []byte, []byte) { return td, currentBlock, genesis } + currentBlock := common.Hash{1} + genesis := common.Hash{2} + eth.chainManager.status = func() (*big.Int, common.Hash, common.Hash) { return td, currentBlock, genesis } go eth.run() - statusMsg := p2p.NewMsg(4) - eth.In(statusMsg) - delay := 1 * time.Second - eth.checkError(ErrNoStatusMsg, delay) - var status statusMsgData - eth.checkMsg(0, StatusMsg, &status) // first outgoing msg should be StatusMsg - if status.TD.Cmp(td) != 0 || - status.ProtocolVersion != ProtocolVersion || - status.NetworkId != NetworkId || - status.TD.Cmp(td) != 0 || - bytes.Compare(status.CurrentBlock, currentBlock) != 0 || - bytes.Compare(status.GenesisBlock, genesis) != 0 { - t.Errorf("incorrect outgoing status") + + tests := []struct { + code uint64 + data interface{} + wantErrorCode int + }{ + { + code: TxMsg, data: []interface{}{}, + wantErrorCode: ErrNoStatusMsg, + }, + { + code: StatusMsg, data: statusMsgData{10, NetworkId, td, currentBlock, genesis}, + wantErrorCode: ErrProtocolVersionMismatch, + }, + { + code: StatusMsg, data: statusMsgData{ProtocolVersion, 999, td, currentBlock, genesis}, + wantErrorCode: ErrNetworkIdMismatch, + }, + { + code: StatusMsg, data: statusMsgData{ProtocolVersion, NetworkId, td, currentBlock, common.Hash{3}}, + wantErrorCode: ErrGenesisBlockMismatch, + }, } + for _, test := range tests { + // first outgoing msg should be StatusMsg. + err := p2p.ExpectMsg(eth, StatusMsg, &statusMsgData{ + ProtocolVersion: ProtocolVersion, + NetworkId: NetworkId, + TD: td, + CurrentBlock: currentBlock, + GenesisBlock: genesis, + }) + if err != nil { + t.Fatalf("incorrect outgoing status: %v", err) + } - eth.reset() - go eth.run() - statusMsg = p2p.NewMsg(0, uint32(48), uint32(0), td, currentBlock, genesis) - eth.In(statusMsg) - eth.checkError(ErrProtocolVersionMismatch, delay) - - eth.reset() - go eth.run() - statusMsg = p2p.NewMsg(0, uint32(49), uint32(1), td, currentBlock, genesis) - eth.In(statusMsg) - eth.checkError(ErrNetworkIdMismatch, delay) - - eth.reset() - go eth.run() - statusMsg = p2p.NewMsg(0, uint32(49), uint32(0), td, currentBlock, []byte{3}) - eth.In(statusMsg) - eth.checkError(ErrGenesisBlockMismatch, delay) + // the send call might hang until reset because + // the protocol might not read the payload. + go p2p.Send(eth, test.code, test.data) + eth.checkError(test.wantErrorCode, 1*time.Second) + eth.reset() + go eth.run() + } } diff --git a/whisper/envelope.go b/whisper/envelope.go index 577638046..9ec9fc318 100644 --- a/whisper/envelope.go +++ b/whisper/envelope.go @@ -6,9 +6,9 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" ) diff --git a/whisper/peer.go b/whisper/peer.go index 4bd9428f5..ee5bffd0b 100644 --- a/whisper/peer.go +++ b/whisper/peer.go @@ -77,12 +77,11 @@ func (self *peer) broadcast(envelopes []*Envelope) error { } if i > 0 { - if err := p2p.EncodeMsg(self.ws, envelopesMsg, envs[:i]...); err != nil { + if err := p2p.Send(self.ws, envelopesMsg, envs[:i]); err != nil { return err } self.peer.DebugDetailln("broadcasted", i, "message(s)") } - return nil } @@ -92,7 +91,7 @@ func (self *peer) addKnown(envelope *Envelope) { func (self *peer) handleStatus() error { ws := self.ws - if err := ws.WriteMsg(self.statusMsg()); err != nil { + if err := p2p.SendItems(ws, statusMsg, protocolVersion); err != nil { return err } msg, err := ws.ReadMsg() @@ -115,7 +114,3 @@ func (self *peer) handleStatus() error { } return msg.Discard() // ignore anything after protocol version } - -func (self *peer) statusMsg() p2p.Msg { - return p2p.NewMsg(statusMsg, protocolVersion) -} From 29eb2209101cfec758803bc52582900dad246f7f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Mar 2015 17:18:55 +0100 Subject: [PATCH 45/78] :-) --- core/chain_manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index ff37ea28a..915fa704f 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -466,7 +466,6 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } - // XXX put this in a goroutine? go self.eventMux.Post(queueEvent) return nil From df5901fdc58565448629a9bfd5ccecc1c5a5b349 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Mar 2015 22:45:03 +0100 Subject: [PATCH 46/78] Removed more casts --- cmd/ethtest/main.go | 3 +-- common/big.go | 4 ++-- vm/common.go | 9 +++++---- vm/context.go | 4 ---- vm/vm.go | 18 ++++++------------ 5 files changed, 14 insertions(+), 24 deletions(-) diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go index ee6bcc540..f2f7d27f3 100644 --- a/cmd/ethtest/main.go +++ b/cmd/ethtest/main.go @@ -24,7 +24,6 @@ package main import ( "bytes" "encoding/json" - "fmt" "io" "io/ioutil" "log" @@ -210,7 +209,7 @@ func RunVmTest(r io.Reader) (failed int) { } if failed == 1 { - fmt.Println(string(statedb.Dump())) + helper.Log.Infoln(string(statedb.Dump())) } logger.Flush() diff --git a/common/big.go b/common/big.go index 750b28f85..8fe9d8bef 100644 --- a/common/big.go +++ b/common/big.go @@ -104,7 +104,7 @@ func BigCopy(src *big.Int) *big.Int { // // Returns the maximum size big integer func BigMax(x, y *big.Int) *big.Int { - if x.Cmp(y) <= 0 { + if x.Cmp(y) < 0 { return y } @@ -115,7 +115,7 @@ func BigMax(x, y *big.Int) *big.Int { // // Returns the minimum size big integer func BigMin(x, y *big.Int) *big.Int { - if x.Cmp(y) >= 0 { + if x.Cmp(y) > 0 { return y } diff --git a/vm/common.go b/vm/common.go index 5441a4ac5..8d8f4253f 100644 --- a/vm/common.go +++ b/vm/common.go @@ -73,9 +73,10 @@ func toValue(val *big.Int) interface{} { return val } -func getData(data []byte, start, size uint64) []byte { - x := uint64(math.Min(float64(start), float64(len(data)))) - y := uint64(math.Min(float64(x+size), float64(len(data)))) +func getData(data []byte, start, size *big.Int) []byte { + dlen := big.NewInt(int64(len(data))) - return common.RightPadBytes(data[x:y], int(size)) + s := common.BigMin(start, dlen) + e := common.BigMin(new(big.Int).Add(s, size), dlen) + return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64())) } diff --git a/vm/context.go b/vm/context.go index ea70f2376..e73199b77 100644 --- a/vm/context.go +++ b/vm/context.go @@ -64,10 +64,6 @@ func (c *Context) GetRangeValue(x, size uint64) []byte { return common.RightPadBytes(c.Code[x:y], int(size)) } -func (c *Context) GetCode(x, size uint64) []byte { - return getData(c.Code, x, size) -} - func (c *Context) Return(ret []byte) []byte { // Return the remaining gas to the caller c.caller.ReturnGas(c.Gas, c.Price) diff --git a/vm/vm.go b/vm/vm.go index 123da6b03..7400a48c4 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -445,14 +445,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { cOff = stack.pop() l = stack.pop() ) - var data []byte - if cOff.Cmp(big.NewInt(int64(len(callData)))) <= 0 { - data = getData(callData, cOff.Uint64(), l.Uint64()) - } + data := getData(callData, cOff, l) mem.Set(mOff.Uint64(), l.Uint64(), data) - self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, data) + self.Printf(" => [%v, %v, %v]", mOff, cOff, l) case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { @@ -482,10 +479,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { l = stack.pop() ) - var codeCopy []byte - if cOff.Cmp(big.NewInt(int64(len(code)))) <= 0 { - codeCopy = getData(code, cOff.Uint64(), l.Uint64()) - } + codeCopy := getData(code, cOff, l) mem.Set(mOff.Uint64(), l.Uint64(), codeCopy) @@ -585,11 +579,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => 0x%x", val) case MSTORE8: - off, val := stack.pop(), stack.pop() + off, val := stack.pop().Int64(), stack.pop().Int64() - mem.store[off.Int64()] = byte(val.Int64() & 0xff) + mem.store[off] = byte(val & 0xff) - self.Printf(" => [%v] 0x%x", off, val) + self.Printf(" => [%v] 0x%x", off, mem.store[off]) case SLOAD: loc := common.BigToHash(stack.pop()) val := common.Bytes2Big(statedb.GetState(context.Address(), loc)) From 62236dd95e6d069b8bd9895c9998676b8d946d37 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Mar 2015 23:20:41 +0100 Subject: [PATCH 47/78] copy over loop --- common/types.go | 11 ++--------- core/types/common.go | 7 ++----- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/common/types.go b/common/types.go index 38044d5c8..daefcde11 100644 --- a/common/types.go +++ b/common/types.go @@ -35,10 +35,7 @@ func (h *Hash) SetBytes(b []byte) { b = b[len(b)-hashLength:] } - // reverse loop - for i := len(b) - 1; i >= 0; i-- { - h[hashLength-len(b)+i] = b[i] - } + copy(h[hashLength-len(b):], b) } // Set string `s` to h. If s is larger than len(h) it will panic @@ -73,11 +70,7 @@ func (a *Address) SetBytes(b []byte) { if len(b) > len(a) { b = b[len(b)-addressLength:] } - - // reverse loop - for i := len(b) - 1; i >= 0; i-- { - a[addressLength-len(b)+i] = b[i] - } + copy(a[addressLength-len(b):], b) } // Set string `s` to a. If s is larger than len(a) it will panic diff --git a/core/types/common.go b/core/types/common.go index 4e885c4c6..ce1090919 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -3,8 +3,8 @@ package types import ( "math/big" - "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/state" "fmt" ) @@ -28,10 +28,7 @@ func (b *Bloom) SetBytes(d []byte) { panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d))) } - // reverse loop - for i := len(d) - 1; i >= 0; i-- { - b[bloomLength-len(d)+i] = b[i] - } + copy(b[bloomLength-len(d):], d) } func (b Bloom) Big() *big.Int { From d8fe8f60e84f599a92783bd690b8d3477cf5a595 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Mar 2015 11:19:12 +0100 Subject: [PATCH 48/78] updated ethash --- Godeps/Godeps.json | 4 +- .../src/github.com/ethereum/ethash/ethash.go | 5 +- .../ethereum/ethash/js/cache_sizes.js | 329 ++++++++++++++ .../ethereum/ethash/js/dag_sizes.js | 412 ++++++++++++++++++ .../github.com/ethereum/ethash/js/ethash.js | 326 +++++++------- .../ethereum/ethash/js/package.json | 21 + .../ethereum/ethash/js/test/seedHash.js | 48 ++ .../ethereum/ethash/js/{ => test}/test.js | 19 +- .../src/github.com/ethereum/ethash/setup.py | 4 +- .../ethash/src/libethash/data_sizes.h | 4 +- .../ethereum/ethash/src/libethash/ethash.h | 43 +- .../ethereum/ethash/src/libethash/internal.c | 92 +++- .../ethereum/ethash/src/libethash/internal.h | 4 +- .../ethereum/ethash/src/python/core.c | 14 +- .../ethereum/ethash/test/c/test.cpp | 10 +- .../github.com/ethereum/ethash/test/test.sh | 7 +- 16 files changed, 1106 insertions(+), 236 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/cache_sizes.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/dag_sizes.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/package.json create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/test/seedHash.js rename Godeps/_workspace/src/github.com/ethereum/ethash/js/{ => test}/test.js (85%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e6eab504d..0cdb4b026 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -22,8 +22,8 @@ }, { "ImportPath": "github.com/ethereum/ethash", - "Comment": "v23-12-g149261a", - "Rev": "149261a5d7cafc3943cbcf1d370082ec70d81e8b" + "Comment": "v23.1-25-gc0429f2", + "Rev": "c0429f268b62e2238b684d4b5495f8ff24115424" }, { "ImportPath": "github.com/ethereum/serpent-go", diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go index 7328bc922..8c325d25d 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go @@ -31,8 +31,8 @@ import ( "time" "unsafe" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" ) @@ -360,8 +360,7 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte } func (pow *Ethash) Verify(block pow.Block) bool { - - return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), block.Nonce()) + return pow.verify(block.HashNoNonce().Bytes(), block.MixDigest().Bytes(), block.Difficulty(), block.NumberU64(), block.Nonce()) } func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, blockNum uint64, nonce uint64) bool { diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/cache_sizes.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/cache_sizes.js new file mode 100644 index 000000000..18c567452 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/cache_sizes.js @@ -0,0 +1,329 @@ +module.exports = [ +16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072, + 17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088, + 18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208, + 19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968, + 20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216, + 21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104, + 22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096, + 23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112, + 24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488, + 25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096, + 25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472, + 26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744, + 27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504, + 28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752, + 29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976, + 30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248, + 31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392, + 32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768, + 33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992, + 34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984, + 35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976, + 36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656, + 36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904, + 37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672, + 38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632, + 39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032, + 40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304, + 41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912, + 42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696, + 43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432, + 44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448, + 45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208, + 46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328, + 47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936, + 47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312, + 48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712, + 49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472, + 50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848, + 51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968, + 52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576, + 53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744, + 54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248, + 55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856, + 56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488, + 57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632, + 58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984, + 58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512, + 59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968, + 60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752, + 61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512, + 62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656, + 63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392, + 64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792, + 65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296, + 66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672, + 67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304, + 68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912, + 69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184, + 69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816, + 70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168, + 71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568, + 72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944, + 73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832, + 74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544, + 75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072, + 76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832, + 77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336, + 78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664, + 79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472, + 80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848, + 81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304, + 81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984, + 82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464, + 83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608, + 84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496, + 85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112, + 86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632, + 87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264, + 88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384, + 89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376, + 90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776, + 91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384, + 92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912, + 92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136, + 93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896, + 94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016, + 95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544, + 96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536, + 97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168, + 98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928, + 99352384, 99482816, 99614272, 99745472, 99876416, 100007104, + 100138048, 100267072, 100401088, 100529984, 100662592, 100791872, + 100925248, 101056064, 101187392, 101317952, 101449408, 101580608, + 101711296, 101841728, 101973824, 102104896, 102235712, 102366016, + 102498112, 102628672, 102760384, 102890432, 103021888, 103153472, + 103284032, 103415744, 103545152, 103677248, 103808576, 103939648, + 104070976, 104201792, 104332736, 104462528, 104594752, 104725952, + 104854592, 104988608, 105118912, 105247808, 105381184, 105511232, + 105643072, 105774784, 105903296, 106037056, 106167872, 106298944, + 106429504, 106561472, 106691392, 106822592, 106954304, 107085376, + 107216576, 107346368, 107478464, 107609792, 107739712, 107872192, + 108003136, 108131392, 108265408, 108396224, 108527168, 108657344, + 108789568, 108920384, 109049792, 109182272, 109312576, 109444928, + 109572928, 109706944, 109837888, 109969088, 110099648, 110230976, + 110362432, 110492992, 110624704, 110755264, 110886208, 111017408, + 111148864, 111279296, 111410752, 111541952, 111673024, 111803456, + 111933632, 112066496, 112196416, 112328512, 112457792, 112590784, + 112715968, 112852672, 112983616, 113114944, 113244224, 113376448, + 113505472, 113639104, 113770304, 113901376, 114031552, 114163264, + 114294592, 114425536, 114556864, 114687424, 114818624, 114948544, + 115080512, 115212224, 115343296, 115473472, 115605184, 115736128, + 115867072, 115997248, 116128576, 116260288, 116391488, 116522944, + 116652992, 116784704, 116915648, 117046208, 117178304, 117308608, + 117440192, 117569728, 117701824, 117833024, 117964096, 118094656, + 118225984, 118357312, 118489024, 118617536, 118749632, 118882112, + 119012416, 119144384, 119275328, 119406016, 119537344, 119668672, + 119798464, 119928896, 120061376, 120192832, 120321728, 120454336, + 120584512, 120716608, 120848192, 120979136, 121109056, 121241408, + 121372352, 121502912, 121634752, 121764416, 121895744, 122027072, + 122157632, 122289088, 122421184, 122550592, 122682944, 122813888, + 122945344, 123075776, 123207488, 123338048, 123468736, 123600704, + 123731264, 123861952, 123993664, 124124608, 124256192, 124386368, + 124518208, 124649024, 124778048, 124911296, 125041088, 125173696, + 125303744, 125432896, 125566912, 125696576, 125829056, 125958592, + 126090304, 126221248, 126352832, 126483776, 126615232, 126746432, + 126876608, 127008704, 127139392, 127270336, 127401152, 127532224, + 127663552, 127794752, 127925696, 128055232, 128188096, 128319424, + 128449856, 128581312, 128712256, 128843584, 128973632, 129103808, + 129236288, 129365696, 129498944, 129629888, 129760832, 129892288, + 130023104, 130154048, 130283968, 130416448, 130547008, 130678336, + 130807616, 130939456, 131071552, 131202112, 131331776, 131464384, + 131594048, 131727296, 131858368, 131987392, 132120256, 132250816, + 132382528, 132513728, 132644672, 132774976, 132905792, 133038016, + 133168832, 133299392, 133429312, 133562048, 133692992, 133823296, + 133954624, 134086336, 134217152, 134348608, 134479808, 134607296, + 134741056, 134872384, 135002944, 135134144, 135265472, 135396544, + 135527872, 135659072, 135787712, 135921472, 136052416, 136182848, + 136313792, 136444864, 136576448, 136707904, 136837952, 136970048, + 137099584, 137232064, 137363392, 137494208, 137625536, 137755712, + 137887424, 138018368, 138149824, 138280256, 138411584, 138539584, + 138672832, 138804928, 138936128, 139066688, 139196864, 139328704, + 139460032, 139590208, 139721024, 139852864, 139984576, 140115776, + 140245696, 140376512, 140508352, 140640064, 140769856, 140902336, + 141032768, 141162688, 141294016, 141426496, 141556544, 141687488, + 141819584, 141949888, 142080448, 142212544, 142342336, 142474432, + 142606144, 142736192, 142868288, 142997824, 143129408, 143258944, + 143392448, 143523136, 143653696, 143785024, 143916992, 144045632, + 144177856, 144309184, 144440768, 144570688, 144701888, 144832448, + 144965056, 145096384, 145227584, 145358656, 145489856, 145620928, + 145751488, 145883072, 146011456, 146144704, 146275264, 146407232, + 146538176, 146668736, 146800448, 146931392, 147062336, 147193664, + 147324224, 147455936, 147586624, 147717056, 147848768, 147979456, + 148110784, 148242368, 148373312, 148503232, 148635584, 148766144, + 148897088, 149028416, 149159488, 149290688, 149420224, 149551552, + 149683136, 149814976, 149943616, 150076352, 150208064, 150338624, + 150470464, 150600256, 150732224, 150862784, 150993088, 151125952, + 151254976, 151388096, 151519168, 151649728, 151778752, 151911104, + 152042944, 152174144, 152304704, 152435648, 152567488, 152698816, + 152828992, 152960576, 153091648, 153222976, 153353792, 153484096, + 153616192, 153747008, 153878336, 154008256, 154139968, 154270912, + 154402624, 154533824, 154663616, 154795712, 154926272, 155057984, + 155188928, 155319872, 155450816, 155580608, 155712064, 155843392, + 155971136, 156106688, 156237376, 156367424, 156499264, 156630976, + 156761536, 156892352, 157024064, 157155008, 157284416, 157415872, + 157545536, 157677248, 157810496, 157938112, 158071744, 158203328, + 158334656, 158464832, 158596288, 158727616, 158858048, 158988992, + 159121216, 159252416, 159381568, 159513152, 159645632, 159776192, + 159906496, 160038464, 160169536, 160300352, 160430656, 160563008, + 160693952, 160822208, 160956352, 161086784, 161217344, 161349184, + 161480512, 161611456, 161742272, 161873216, 162002752, 162135872, + 162266432, 162397888, 162529216, 162660032, 162790976, 162922048, + 163052096, 163184576, 163314752, 163446592, 163577408, 163707968, + 163839296, 163969984, 164100928, 164233024, 164364224, 164494912, + 164625856, 164756672, 164887616, 165019072, 165150016, 165280064, + 165412672, 165543104, 165674944, 165805888, 165936832, 166067648, + 166198336, 166330048, 166461248, 166591552, 166722496, 166854208, + 166985408, 167116736, 167246656, 167378368, 167508416, 167641024, + 167771584, 167903168, 168034112, 168164032, 168295744, 168427456, + 168557632, 168688448, 168819136, 168951616, 169082176, 169213504, + 169344832, 169475648, 169605952, 169738048, 169866304, 169999552, + 170131264, 170262464, 170393536, 170524352, 170655424, 170782016, + 170917696, 171048896, 171179072, 171310784, 171439936, 171573184, + 171702976, 171835072, 171966272, 172097216, 172228288, 172359232, + 172489664, 172621376, 172747712, 172883264, 173014208, 173144512, + 173275072, 173407424, 173539136, 173669696, 173800768, 173931712, + 174063424, 174193472, 174325696, 174455744, 174586816, 174718912, + 174849728, 174977728, 175109696, 175242688, 175374272, 175504832, + 175636288, 175765696, 175898432, 176028992, 176159936, 176291264, + 176422592, 176552512, 176684864, 176815424, 176946496, 177076544, + 177209152, 177340096, 177470528, 177600704, 177731648, 177864256, + 177994816, 178126528, 178257472, 178387648, 178518464, 178650176, + 178781888, 178912064, 179044288, 179174848, 179305024, 179436736, + 179568448, 179698496, 179830208, 179960512, 180092608, 180223808, + 180354752, 180485696, 180617152, 180748096, 180877504, 181009984, + 181139264, 181272512, 181402688, 181532608, 181663168, 181795136, + 181926592, 182057536, 182190016, 182320192, 182451904, 182582336, + 182713792, 182843072, 182976064, 183107264, 183237056, 183368384, + 183494848, 183631424, 183762752, 183893824, 184024768, 184154816, + 184286656, 184417984, 184548928, 184680128, 184810816, 184941248, + 185072704, 185203904, 185335616, 185465408, 185596352, 185727296, + 185859904, 185989696, 186121664, 186252992, 186383552, 186514112, + 186645952, 186777152, 186907328, 187037504, 187170112, 187301824, + 187429184, 187562048, 187693504, 187825472, 187957184, 188087104, + 188218304, 188349376, 188481344, 188609728, 188743616, 188874304, + 189005248, 189136448, 189265088, 189396544, 189528128, 189660992, + 189791936, 189923264, 190054208, 190182848, 190315072, 190447424, + 190577984, 190709312, 190840768, 190971328, 191102656, 191233472, + 191364032, 191495872, 191626816, 191758016, 191888192, 192020288, + 192148928, 192282176, 192413504, 192542528, 192674752, 192805952, + 192937792, 193068608, 193198912, 193330496, 193462208, 193592384, + 193723456, 193854272, 193985984, 194116672, 194247232, 194379712, + 194508352, 194641856, 194772544, 194900672, 195035072, 195166016, + 195296704, 195428032, 195558592, 195690304, 195818176, 195952576, + 196083392, 196214336, 196345792, 196476736, 196607552, 196739008, + 196869952, 197000768, 197130688, 197262784, 197394368, 197523904, + 197656384, 197787584, 197916608, 198049472, 198180544, 198310208, + 198442432, 198573632, 198705088, 198834368, 198967232, 199097792, + 199228352, 199360192, 199491392, 199621696, 199751744, 199883968, + 200014016, 200146624, 200276672, 200408128, 200540096, 200671168, + 200801984, 200933312, 201062464, 201194944, 201326144, 201457472, + 201588544, 201719744, 201850816, 201981632, 202111552, 202244032, + 202374464, 202505152, 202636352, 202767808, 202898368, 203030336, + 203159872, 203292608, 203423296, 203553472, 203685824, 203816896, + 203947712, 204078272, 204208192, 204341056, 204472256, 204603328, + 204733888, 204864448, 204996544, 205125568, 205258304, 205388864, + 205517632, 205650112, 205782208, 205913536, 206044736, 206176192, + 206307008, 206434496, 206569024, 206700224, 206831168, 206961856, + 207093056, 207223616, 207355328, 207486784, 207616832, 207749056, + 207879104, 208010048, 208141888, 208273216, 208404032, 208534336, + 208666048, 208796864, 208927424, 209059264, 209189824, 209321792, + 209451584, 209582656, 209715136, 209845568, 209976896, 210106432, + 210239296, 210370112, 210501568, 210630976, 210763712, 210894272, + 211024832, 211156672, 211287616, 211418176, 211549376, 211679296, + 211812032, 211942592, 212074432, 212204864, 212334016, 212467648, + 212597824, 212727616, 212860352, 212991424, 213120832, 213253952, + 213385024, 213515584, 213645632, 213777728, 213909184, 214040128, + 214170688, 214302656, 214433728, 214564544, 214695232, 214826048, + 214956992, 215089088, 215219776, 215350592, 215482304, 215613248, + 215743552, 215874752, 216005312, 216137024, 216267328, 216399296, + 216530752, 216661696, 216790592, 216923968, 217054528, 217183168, + 217316672, 217448128, 217579072, 217709504, 217838912, 217972672, + 218102848, 218233024, 218364736, 218496832, 218627776, 218759104, + 218888896, 219021248, 219151936, 219281728, 219413056, 219545024, + 219675968, 219807296, 219938624, 220069312, 220200128, 220331456, + 220461632, 220592704, 220725184, 220855744, 220987072, 221117888, + 221249216, 221378368, 221510336, 221642048, 221772736, 221904832, + 222031808, 222166976, 222297536, 222428992, 222559936, 222690368, + 222820672, 222953152, 223083968, 223213376, 223345984, 223476928, + 223608512, 223738688, 223869376, 224001472, 224132672, 224262848, + 224394944, 224524864, 224657344, 224788288, 224919488, 225050432, + 225181504, 225312704, 225443776, 225574592, 225704768, 225834176, + 225966784, 226097216, 226229824, 226360384, 226491712, 226623424, + 226754368, 226885312, 227015104, 227147456, 227278528, 227409472, + 227539904, 227669696, 227802944, 227932352, 228065216, 228196288, + 228326464, 228457792, 228588736, 228720064, 228850112, 228981056, + 229113152, 229243328, 229375936, 229505344, 229636928, 229769152, + 229894976, 230030272, 230162368, 230292416, 230424512, 230553152, + 230684864, 230816704, 230948416, 231079616, 231210944, 231342016, + 231472448, 231603776, 231733952, 231866176, 231996736, 232127296, + 232259392, 232388672, 232521664, 232652608, 232782272, 232914496, + 233043904, 233175616, 233306816, 233438528, 233569984, 233699776, + 233830592, 233962688, 234092224, 234221888, 234353984, 234485312, + 234618304, 234749888, 234880832, 235011776, 235142464, 235274048, + 235403456, 235535936, 235667392, 235797568, 235928768, 236057152, + 236190272, 236322752, 236453312, 236583616, 236715712, 236846528, + 236976448, 237108544, 237239104, 237371072, 237501632, 237630784, + 237764416, 237895232, 238026688, 238157632, 238286912, 238419392, + 238548032, 238681024, 238812608, 238941632, 239075008, 239206336, + 239335232, 239466944, 239599168, 239730496, 239861312, 239992384, + 240122816, 240254656, 240385856, 240516928, 240647872, 240779072, + 240909632, 241040704, 241171904, 241302848, 241433408, 241565248, + 241696192, 241825984, 241958848, 242088256, 242220224, 242352064, + 242481856, 242611648, 242744896, 242876224, 243005632, 243138496, + 243268672, 243400384, 243531712, 243662656, 243793856, 243924544, + 244054592, 244187072, 244316608, 244448704, 244580032, 244710976, + 244841536, 244972864, 245104448, 245233984, 245365312, 245497792, + 245628736, 245759936, 245889856, 246021056, 246152512, 246284224, + 246415168, 246545344, 246675904, 246808384, 246939584, 247070144, + 247199552, 247331648, 247463872, 247593536, 247726016, 247857088, + 247987648, 248116928, 248249536, 248380736, 248512064, 248643008, + 248773312, 248901056, 249036608, 249167552, 249298624, 249429184, + 249560512, 249692096, 249822784, 249954112, 250085312, 250215488, + 250345792, 250478528, 250608704, 250739264, 250870976, 251002816, + 251133632, 251263552, 251395136, 251523904, 251657792, 251789248, + 251919424, 252051392, 252182464, 252313408, 252444224, 252575552, + 252706624, 252836032, 252968512, 253099712, 253227584, 253361728, + 253493056, 253623488, 253754432, 253885504, 254017216, 254148032, + 254279488, 254410432, 254541376, 254672576, 254803264, 254933824, + 255065792, 255196736, 255326528, 255458752, 255589952, 255721408, + 255851072, 255983296, 256114624, 256244416, 256374208, 256507712, + 256636096, 256768832, 256900544, 257031616, 257162176, 257294272, + 257424448, 257555776, 257686976, 257818432, 257949632, 258079552, + 258211136, 258342464, 258473408, 258603712, 258734656, 258867008, + 258996544, 259127744, 259260224, 259391296, 259522112, 259651904, + 259784384, 259915328, 260045888, 260175424, 260308544, 260438336, + 260570944, 260700992, 260832448, 260963776, 261092672, 261226304, + 261356864, 261487936, 261619648, 261750592, 261879872, 262011968, + 262143424, 262274752, 262404416, 262537024, 262667968, 262799296, + 262928704, 263061184, 263191744, 263322944, 263454656, 263585216, + 263716672, 263847872, 263978944, 264108608, 264241088, 264371648, + 264501184, 264632768, 264764096, 264895936, 265024576, 265158464, + 265287488, 265418432, 265550528, 265681216, 265813312, 265943488, + 266075968, 266206144, 266337728, 266468032, 266600384, 266731072, + 266862272, 266993344, 267124288, 267255616, 267386432, 267516992, + 267648704, 267777728, 267910592, 268040512, 268172096, 268302784, + 268435264, 268566208, 268696256, 268828096, 268959296, 269090368, + 269221312, 269352256, 269482688, 269614784, 269745856, 269876416, + 270007616, 270139328, 270270272, 270401216, 270531904, 270663616, + 270791744, 270924736, 271056832, 271186112, 271317184, 271449536, + 271580992, 271711936, 271843136, 271973056, 272105408, 272236352, + 272367296, 272498368, 272629568, 272759488, 272891456, 273022784, + 273153856, 273284672, 273415616, 273547072, 273677632, 273808448, + 273937088, 274071488, 274200896, 274332992, 274463296, 274595392, + 274726208, 274857536, 274988992, 275118656, 275250496, 275382208, + 275513024, 275643968, 275775296, 275906368, 276037184, 276167872, + 276297664, 276429376, 276560576, 276692672, 276822976, 276955072, + 277085632, 277216832, 277347008, 277478848, 277609664, 277740992, + 277868608, 278002624, 278134336, 278265536, 278395328, 278526784, + 278657728, 278789824, 278921152, 279052096, 279182912, 279313088, + 279443776, 279576256, 279706048, 279838528, 279969728, 280099648, + 280230976, 280361408, 280493632, 280622528, 280755392, 280887104, + 281018176, 281147968, 281278912, 281411392, 281542592, 281673152, + 281803712, 281935552, 282066496, 282197312, 282329024, 282458816, + 282590272, 282720832, 282853184, 282983744, 283115072, 283246144, + 283377344, 283508416, 283639744, 283770304, 283901504, 284032576, + 284163136, 284294848, 284426176, 284556992, 284687296, 284819264, + 284950208, 285081536 +]; diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/dag_sizes.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/dag_sizes.js new file mode 100644 index 000000000..ae47b0b03 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/dag_sizes.js @@ -0,0 +1,412 @@ +module.exports = [ + 1073739904, 1082130304, 1090514816, 1098906752, 1107293056, + 1115684224, 1124070016, 1132461952, 1140849536, 1149232768, + 1157627776, 1166013824, 1174404736, 1182786944, 1191180416, + 1199568512, 1207958912, 1216345216, 1224732032, 1233124736, + 1241513344, 1249902464, 1258290304, 1266673792, 1275067264, + 1283453312, 1291844992, 1300234112, 1308619904, 1317010048, + 1325397376, 1333787776, 1342176128, 1350561664, 1358954368, + 1367339392, 1375731584, 1384118144, 1392507008, 1400897408, + 1409284736, 1417673344, 1426062464, 1434451072, 1442839168, + 1451229056, 1459615616, 1468006016, 1476394112, 1484782976, + 1493171584, 1501559168, 1509948032, 1518337664, 1526726528, + 1535114624, 1543503488, 1551892096, 1560278656, 1568669056, + 1577056384, 1585446272, 1593831296, 1602219392, 1610610304, + 1619000192, 1627386752, 1635773824, 1644164224, 1652555648, + 1660943488, 1669332608, 1677721216, 1686109312, 1694497664, + 1702886272, 1711274624, 1719661184, 1728047744, 1736434816, + 1744829056, 1753218944, 1761606272, 1769995904, 1778382464, + 1786772864, 1795157888, 1803550592, 1811937664, 1820327552, + 1828711552, 1837102976, 1845488768, 1853879936, 1862269312, + 1870656896, 1879048064, 1887431552, 1895825024, 1904212096, + 1912601216, 1920988544, 1929379456, 1937765504, 1946156672, + 1954543232, 1962932096, 1971321728, 1979707264, 1988093056, + 1996487552, 2004874624, 2013262208, 2021653888, 2030039936, + 2038430848, 2046819968, 2055208576, 2063596672, 2071981952, + 2080373632, 2088762752, 2097149056, 2105539712, 2113928576, + 2122315136, 2130700672, 2139092608, 2147483264, 2155872128, + 2164257664, 2172642176, 2181035392, 2189426048, 2197814912, + 2206203008, 2214587264, 2222979712, 2231367808, 2239758208, + 2248145024, 2256527744, 2264922752, 2273312128, 2281701248, + 2290086272, 2298476672, 2306867072, 2315251072, 2323639168, + 2332032128, 2340420224, 2348808064, 2357196416, 2365580416, + 2373966976, 2382363008, 2390748544, 2399139968, 2407530368, + 2415918976, 2424307328, 2432695424, 2441084288, 2449472384, + 2457861248, 2466247808, 2474637184, 2483026816, 2491414144, + 2499803776, 2508191872, 2516582272, 2524970368, 2533359232, + 2541743488, 2550134144, 2558525056, 2566913408, 2575301504, + 2583686528, 2592073856, 2600467328, 2608856192, 2617240448, + 2625631616, 2634022016, 2642407552, 2650796416, 2659188352, + 2667574912, 2675965312, 2684352896, 2692738688, 2701130624, + 2709518464, 2717907328, 2726293376, 2734685056, 2743073152, + 2751462016, 2759851648, 2768232832, 2776625536, 2785017728, + 2793401984, 2801794432, 2810182016, 2818571648, 2826959488, + 2835349376, 2843734144, 2852121472, 2860514432, 2868900992, + 2877286784, 2885676928, 2894069632, 2902451584, 2910843008, + 2919234688, 2927622784, 2936011648, 2944400768, 2952789376, + 2961177728, 2969565568, 2977951616, 2986338944, 2994731392, + 3003120256, 3011508352, 3019895936, 3028287104, 3036675968, + 3045063808, 3053452928, 3061837696, 3070228352, 3078615424, + 3087003776, 3095394944, 3103782272, 3112173184, 3120562048, + 3128944768, 3137339264, 3145725056, 3154109312, 3162505088, + 3170893184, 3179280256, 3187669376, 3196056704, 3204445568, + 3212836736, 3221224064, 3229612928, 3238002304, 3246391168, + 3254778496, 3263165824, 3271556224, 3279944576, 3288332416, + 3296719232, 3305110912, 3313500032, 3321887104, 3330273152, + 3338658944, 3347053184, 3355440512, 3363827072, 3372220288, + 3380608384, 3388997504, 3397384576, 3405774208, 3414163072, + 3422551936, 3430937984, 3439328384, 3447714176, 3456104576, + 3464493952, 3472883584, 3481268864, 3489655168, 3498048896, + 3506434432, 3514826368, 3523213952, 3531603584, 3539987072, + 3548380288, 3556763264, 3565157248, 3573545344, 3581934464, + 3590324096, 3598712704, 3607098752, 3615488384, 3623877248, + 3632265856, 3640646528, 3649043584, 3657430144, 3665821568, + 3674207872, 3682597504, 3690984832, 3699367808, 3707764352, + 3716152448, 3724541056, 3732925568, 3741318016, 3749706368, + 3758091136, 3766481536, 3774872704, 3783260032, 3791650432, + 3800036224, 3808427648, 3816815488, 3825204608, 3833592704, + 3841981568, 3850370432, 3858755968, 3867147904, 3875536256, + 3883920512, 3892313728, 3900702592, 3909087872, 3917478784, + 3925868416, 3934256512, 3942645376, 3951032192, 3959422336, + 3967809152, 3976200064, 3984588416, 3992974976, 4001363584, + 4009751168, 4018141312, 4026530432, 4034911616, 4043308928, + 4051695488, 4060084352, 4068472448, 4076862848, 4085249408, + 4093640576, 4102028416, 4110413696, 4118805632, 4127194496, + 4135583104, 4143971968, 4152360832, 4160746112, 4169135744, + 4177525888, 4185912704, 4194303616, 4202691968, 4211076736, + 4219463552, 4227855488, 4236246656, 4244633728, 4253022848, + 4261412224, 4269799808, 4278184832, 4286578048, 4294962304, + 4303349632, 4311743104, 4320130432, 4328521088, 4336909184, + 4345295488, 4353687424, 4362073472, 4370458496, 4378852736, + 4387238528, 4395630208, 4404019072, 4412407424, 4420790656, + 4429182848, 4437571456, 4445962112, 4454344064, 4462738048, + 4471119232, 4479516544, 4487904128, 4496289664, 4504682368, + 4513068416, 4521459584, 4529846144, 4538232704, 4546619776, + 4555010176, 4563402112, 4571790208, 4580174464, 4588567936, + 4596957056, 4605344896, 4613734016, 4622119808, 4630511488, + 4638898816, 4647287936, 4655675264, 4664065664, 4672451968, + 4680842624, 4689231488, 4697620352, 4706007424, 4714397056, + 4722786176, 4731173248, 4739562368, 4747951744, 4756340608, + 4764727936, 4773114496, 4781504384, 4789894784, 4798283648, + 4806667648, 4815059584, 4823449472, 4831835776, 4840226176, + 4848612224, 4857003392, 4865391488, 4873780096, 4882169728, + 4890557312, 4898946944, 4907333248, 4915722368, 4924110976, + 4932499328, 4940889728, 4949276032, 4957666432, 4966054784, + 4974438016, 4982831488, 4991221376, 4999607168, 5007998848, + 5016386432, 5024763776, 5033164672, 5041544576, 5049941888, + 5058329728, 5066717056, 5075107456, 5083494272, 5091883904, + 5100273536, 5108662144, 5117048192, 5125436032, 5133827456, + 5142215296, 5150605184, 5158993024, 5167382144, 5175769472, + 5184157568, 5192543872, 5200936064, 5209324928, 5217711232, + 5226102656, 5234490496, 5242877312, 5251263872, 5259654016, + 5268040832, 5276434304, 5284819328, 5293209728, 5301598592, + 5309986688, 5318374784, 5326764416, 5335151488, 5343542144, + 5351929472, 5360319872, 5368706944, 5377096576, 5385484928, + 5393871232, 5402263424, 5410650496, 5419040384, 5427426944, + 5435816576, 5444205952, 5452594816, 5460981376, 5469367936, + 5477760896, 5486148736, 5494536832, 5502925952, 5511315328, + 5519703424, 5528089984, 5536481152, 5544869504, 5553256064, + 5561645696, 5570032768, 5578423936, 5586811264, 5595193216, + 5603585408, 5611972736, 5620366208, 5628750464, 5637143936, + 5645528192, 5653921408, 5662310272, 5670694784, 5679082624, + 5687474048, 5695864448, 5704251008, 5712641408, 5721030272, + 5729416832, 5737806208, 5746194304, 5754583936, 5762969984, + 5771358592, 5779748224, 5788137856, 5796527488, 5804911232, + 5813300608, 5821692544, 5830082176, 5838468992, 5846855552, + 5855247488, 5863636096, 5872024448, 5880411008, 5888799872, + 5897186432, 5905576832, 5913966976, 5922352768, 5930744704, + 5939132288, 5947522432, 5955911296, 5964299392, 5972688256, + 5981074304, 5989465472, 5997851008, 6006241408, 6014627968, + 6023015552, 6031408256, 6039796096, 6048185216, 6056574848, + 6064963456, 6073351808, 6081736064, 6090128768, 6098517632, + 6106906496, 6115289216, 6123680896, 6132070016, 6140459648, + 6148849024, 6157237376, 6165624704, 6174009728, 6182403712, + 6190792064, 6199176064, 6207569792, 6215952256, 6224345216, + 6232732544, 6241124224, 6249510272, 6257899136, 6266287744, + 6274676864, 6283065728, 6291454336, 6299843456, 6308232064, + 6316620928, 6325006208, 6333395584, 6341784704, 6350174848, + 6358562176, 6366951296, 6375337856, 6383729536, 6392119168, + 6400504192, 6408895616, 6417283456, 6425673344, 6434059136, + 6442444672, 6450837376, 6459223424, 6467613056, 6476004224, + 6484393088, 6492781952, 6501170048, 6509555072, 6517947008, + 6526336384, 6534725504, 6543112832, 6551500672, 6559888768, + 6568278656, 6576662912, 6585055616, 6593443456, 6601834112, + 6610219648, 6618610304, 6626999168, 6635385472, 6643777408, + 6652164224, 6660552832, 6668941952, 6677330048, 6685719424, + 6694107776, 6702493568, 6710882176, 6719274112, 6727662976, + 6736052096, 6744437632, 6752825984, 6761213824, 6769604224, + 6777993856, 6786383488, 6794770816, 6803158144, 6811549312, + 6819937664, 6828326528, 6836706176, 6845101696, 6853491328, + 6861880448, 6870269312, 6878655104, 6887046272, 6895433344, + 6903822208, 6912212864, 6920596864, 6928988288, 6937377152, + 6945764992, 6954149248, 6962544256, 6970928768, 6979317376, + 6987709312, 6996093824, 7004487296, 7012875392, 7021258624, + 7029652352, 7038038912, 7046427776, 7054818944, 7063207808, + 7071595136, 7079980928, 7088372608, 7096759424, 7105149824, + 7113536896, 7121928064, 7130315392, 7138699648, 7147092352, + 7155479168, 7163865728, 7172249984, 7180648064, 7189036672, + 7197424768, 7205810816, 7214196608, 7222589824, 7230975104, + 7239367552, 7247755904, 7256145536, 7264533376, 7272921472, + 7281308032, 7289694848, 7298088832, 7306471808, 7314864512, + 7323253888, 7331643008, 7340029568, 7348419712, 7356808832, + 7365196672, 7373585792, 7381973888, 7390362752, 7398750592, + 7407138944, 7415528576, 7423915648, 7432302208, 7440690304, + 7449080192, 7457472128, 7465860992, 7474249088, 7482635648, + 7491023744, 7499412608, 7507803008, 7516192384, 7524579968, + 7532967296, 7541358464, 7549745792, 7558134656, 7566524032, + 7574912896, 7583300992, 7591690112, 7600075136, 7608466816, + 7616854912, 7625244544, 7633629824, 7642020992, 7650410368, + 7658794112, 7667187328, 7675574912, 7683961984, 7692349568, + 7700739712, 7709130368, 7717519232, 7725905536, 7734295424, + 7742683264, 7751069056, 7759457408, 7767849088, 7776238208, + 7784626816, 7793014912, 7801405312, 7809792128, 7818179968, + 7826571136, 7834957184, 7843347328, 7851732352, 7860124544, + 7868512384, 7876902016, 7885287808, 7893679744, 7902067072, + 7910455936, 7918844288, 7927230848, 7935622784, 7944009344, + 7952400256, 7960786048, 7969176704, 7977565312, 7985953408, + 7994339968, 8002730368, 8011119488, 8019508096, 8027896192, + 8036285056, 8044674688, 8053062272, 8061448832, 8069838464, + 8078227328, 8086616704, 8095006592, 8103393664, 8111783552, + 8120171392, 8128560256, 8136949376, 8145336704, 8153726848, + 8162114944, 8170503296, 8178891904, 8187280768, 8195669632, + 8204058496, 8212444544, 8220834176, 8229222272, 8237612672, + 8246000768, 8254389376, 8262775168, 8271167104, 8279553664, + 8287944064, 8296333184, 8304715136, 8313108352, 8321497984, + 8329885568, 8338274432, 8346663296, 8355052928, 8363441536, + 8371828352, 8380217984, 8388606592, 8396996224, 8405384576, + 8413772672, 8422161536, 8430549376, 8438939008, 8447326592, + 8455715456, 8464104832, 8472492928, 8480882048, 8489270656, + 8497659776, 8506045312, 8514434944, 8522823808, 8531208832, + 8539602304, 8547990656, 8556378752, 8564768384, 8573154176, + 8581542784, 8589933952, 8598322816, 8606705024, 8615099264, + 8623487872, 8631876992, 8640264064, 8648653952, 8657040256, + 8665430656, 8673820544, 8682209152, 8690592128, 8698977152, + 8707374464, 8715763328, 8724151424, 8732540032, 8740928384, + 8749315712, 8757704576, 8766089344, 8774480768, 8782871936, + 8791260032, 8799645824, 8808034432, 8816426368, 8824812928, + 8833199488, 8841591424, 8849976448, 8858366336, 8866757248, + 8875147136, 8883532928, 8891923328, 8900306816, 8908700288, + 8917088384, 8925478784, 8933867392, 8942250368, 8950644608, + 8959032704, 8967420544, 8975809664, 8984197504, 8992584064, + 9000976256, 9009362048, 9017752448, 9026141312, 9034530688, + 9042917504, 9051307904, 9059694208, 9068084864, 9076471424, + 9084861824, 9093250688, 9101638528, 9110027648, 9118416512, + 9126803584, 9135188096, 9143581312, 9151969664, 9160356224, + 9168747136, 9177134464, 9185525632, 9193910144, 9202302848, + 9210690688, 9219079552, 9227465344, 9235854464, 9244244864, + 9252633472, 9261021824, 9269411456, 9277799296, 9286188928, + 9294574208, 9302965888, 9311351936, 9319740032, 9328131968, + 9336516736, 9344907392, 9353296768, 9361685888, 9370074752, + 9378463616, 9386849408, 9395239808, 9403629184, 9412016512, + 9420405376, 9428795008, 9437181568, 9445570688, 9453960832, + 9462346624, 9470738048, 9479121536, 9487515008, 9495903616, + 9504289664, 9512678528, 9521067904, 9529456256, 9537843584, + 9546233728, 9554621312, 9563011456, 9571398784, 9579788672, + 9588178304, 9596567168, 9604954496, 9613343104, 9621732992, + 9630121856, 9638508416, 9646898816, 9655283584, 9663675776, + 9672061312, 9680449664, 9688840064, 9697230464, 9705617536, + 9714003584, 9722393984, 9730772608, 9739172224, 9747561088, + 9755945344, 9764338816, 9772726144, 9781116544, 9789503872, + 9797892992, 9806282624, 9814670464, 9823056512, 9831439232, + 9839833984, 9848224384, 9856613504, 9865000576, 9873391232, + 9881772416, 9890162816, 9898556288, 9906940544, 9915333248, + 9923721088, 9932108672, 9940496512, 9948888448, 9957276544, + 9965666176, 9974048384, 9982441088, 9990830464, 9999219584, + 10007602816, 10015996544, 10024385152, 10032774016, 10041163648, + 10049548928, 10057940096, 10066329472, 10074717824, 10083105152, + 10091495296, 10099878784, 10108272256, 10116660608, 10125049216, + 10133437312, 10141825664, 10150213504, 10158601088, 10166991232, + 10175378816, 10183766144, 10192157312, 10200545408, 10208935552, + 10217322112, 10225712768, 10234099328, 10242489472, 10250876032, + 10259264896, 10267656064, 10276042624, 10284429184, 10292820352, + 10301209472, 10309598848, 10317987712, 10326375296, 10334763392, + 10343153536, 10351541632, 10359930752, 10368318592, 10376707456, + 10385096576, 10393484672, 10401867136, 10410262144, 10418647424, + 10427039104, 10435425664, 10443810176, 10452203648, 10460589952, + 10468982144, 10477369472, 10485759104, 10494147712, 10502533504, + 10510923392, 10519313536, 10527702656, 10536091264, 10544478592, + 10552867712, 10561255808, 10569642368, 10578032768, 10586423168, + 10594805632, 10603200128, 10611588992, 10619976064, 10628361344, + 10636754048, 10645143424, 10653531776, 10661920384, 10670307968, + 10678696832, 10687086464, 10695475072, 10703863168, 10712246144, + 10720639616, 10729026688, 10737414784, 10745806208, 10754190976, + 10762581376, 10770971264, 10779356288, 10787747456, 10796135552, + 10804525184, 10812915584, 10821301888, 10829692288, 10838078336, + 10846469248, 10854858368, 10863247232, 10871631488, 10880023424, + 10888412032, 10896799616, 10905188992, 10913574016, 10921964672, + 10930352768, 10938742912, 10947132544, 10955518592, 10963909504, + 10972298368, 10980687488, 10989074816, 10997462912, 11005851776, + 11014241152, 11022627712, 11031017344, 11039403904, 11047793024, + 11056184704, 11064570752, 11072960896, 11081343872, 11089737856, + 11098128256, 11106514816, 11114904448, 11123293568, 11131680128, + 11140065152, 11148458368, 11156845696, 11165236864, 11173624192, + 11182013824, 11190402688, 11198790784, 11207179136, 11215568768, + 11223957376, 11232345728, 11240734592, 11249122688, 11257511296, + 11265899648, 11274285952, 11282675584, 11291065472, 11299452544, + 11307842432, 11316231296, 11324616832, 11333009024, 11341395584, + 11349782656, 11358172288, 11366560384, 11374950016, 11383339648, + 11391721856, 11400117376, 11408504192, 11416893568, 11425283456, + 11433671552, 11442061184, 11450444672, 11458837888, 11467226752, + 11475611776, 11484003968, 11492392064, 11500780672, 11509169024, + 11517550976, 11525944448, 11534335616, 11542724224, 11551111808, + 11559500672, 11567890304, 11576277376, 11584667008, 11593056128, + 11601443456, 11609830016, 11618221952, 11626607488, 11634995072, + 11643387776, 11651775104, 11660161664, 11668552576, 11676940928, + 11685330304, 11693718656, 11702106496, 11710496128, 11718882688, + 11727273088, 11735660416, 11744050048, 11752437376, 11760824704, + 11769216128, 11777604736, 11785991296, 11794381952, 11802770048, + 11811157888, 11819548544, 11827932544, 11836324736, 11844713344, + 11853100928, 11861486464, 11869879936, 11878268032, 11886656896, + 11895044992, 11903433088, 11911822976, 11920210816, 11928600448, + 11936987264, 11945375872, 11953761152, 11962151296, 11970543488, + 11978928512, 11987320448, 11995708288, 12004095104, 12012486272, + 12020875136, 12029255552, 12037652096, 12046039168, 12054429568, + 12062813824, 12071206528, 12079594624, 12087983744, 12096371072, + 12104759936, 12113147264, 12121534592, 12129924992, 12138314624, + 12146703232, 12155091584, 12163481216, 12171864704, 12180255872, + 12188643968, 12197034112, 12205424512, 12213811328, 12222199424, + 12230590336, 12238977664, 12247365248, 12255755392, 12264143488, + 12272531584, 12280920448, 12289309568, 12297694592, 12306086528, + 12314475392, 12322865024, 12331253632, 12339640448, 12348029312, + 12356418944, 12364805248, 12373196672, 12381580928, 12389969024, + 12398357632, 12406750592, 12415138432, 12423527552, 12431916416, + 12440304512, 12448692352, 12457081216, 12465467776, 12473859968, + 12482245504, 12490636672, 12499025536, 12507411584, 12515801728, + 12524190592, 12532577152, 12540966272, 12549354368, 12557743232, + 12566129536, 12574523264, 12582911872, 12591299456, 12599688064, + 12608074624, 12616463488, 12624845696, 12633239936, 12641631616, + 12650019968, 12658407296, 12666795136, 12675183232, 12683574656, + 12691960192, 12700350592, 12708740224, 12717128576, 12725515904, + 12733906816, 12742295168, 12750680192, 12759071872, 12767460736, + 12775848832, 12784236928, 12792626816, 12801014656, 12809404288, + 12817789312, 12826181504, 12834568832, 12842954624, 12851345792, + 12859732352, 12868122496, 12876512128, 12884901248, 12893289088, + 12901672832, 12910067584, 12918455168, 12926842496, 12935232896, + 12943620736, 12952009856, 12960396928, 12968786816, 12977176192, + 12985563776, 12993951104, 13002341504, 13010730368, 13019115392, + 13027506304, 13035895168, 13044272512, 13052673152, 13061062528, + 13069446272, 13077838976, 13086227072, 13094613632, 13103000192, + 13111393664, 13119782528, 13128157568, 13136559232, 13144945024, + 13153329536, 13161724288, 13170111872, 13178502784, 13186884736, + 13195279744, 13203667072, 13212057472, 13220445824, 13228832128, + 13237221248, 13245610624, 13254000512, 13262388352, 13270777472, + 13279166336, 13287553408, 13295943296, 13304331904, 13312719488, + 13321108096, 13329494656, 13337885824, 13346274944, 13354663808, + 13363051136, 13371439232, 13379825024, 13388210816, 13396605056, + 13404995456, 13413380224, 13421771392, 13430159744, 13438546048, + 13446937216, 13455326848, 13463708288, 13472103808, 13480492672, + 13488875648, 13497269888, 13505657728, 13514045312, 13522435712, + 13530824576, 13539210112, 13547599232, 13555989376, 13564379008, + 13572766336, 13581154432, 13589544832, 13597932928, 13606320512, + 13614710656, 13623097472, 13631477632, 13639874944, 13648264064, + 13656652928, 13665041792, 13673430656, 13681818496, 13690207616, + 13698595712, 13706982272, 13715373184, 13723762048, 13732150144, + 13740536704, 13748926592, 13757316224, 13765700992, 13774090112, + 13782477952, 13790869376, 13799259008, 13807647872, 13816036736, + 13824425344, 13832814208, 13841202304, 13849591424, 13857978752, + 13866368896, 13874754688, 13883145344, 13891533184, 13899919232, + 13908311168, 13916692096, 13925085056, 13933473152, 13941866368, + 13950253696, 13958643584, 13967032192, 13975417216, 13983807616, + 13992197504, 14000582272, 14008973696, 14017363072, 14025752192, + 14034137984, 14042528384, 14050918016, 14059301504, 14067691648, + 14076083584, 14084470144, 14092852352, 14101249664, 14109635968, + 14118024832, 14126407552, 14134804352, 14143188608, 14151577984, + 14159968384, 14168357248, 14176741504, 14185127296, 14193521024, + 14201911424, 14210301824, 14218685056, 14227067264, 14235467392, + 14243855488, 14252243072, 14260630144, 14269021568, 14277409408, + 14285799296, 14294187904, 14302571392, 14310961792, 14319353728, + 14327738752, 14336130944, 14344518784, 14352906368, 14361296512, + 14369685376, 14378071424, 14386462592, 14394848128, 14403230848, + 14411627392, 14420013952, 14428402304, 14436793472, 14445181568, + 14453569664, 14461959808, 14470347904, 14478737024, 14487122816, + 14495511424, 14503901824, 14512291712, 14520677504, 14529064832, + 14537456768, 14545845632, 14554234496, 14562618496, 14571011456, + 14579398784, 14587789184, 14596172672, 14604564608, 14612953984, + 14621341312, 14629724288, 14638120832, 14646503296, 14654897536, + 14663284864, 14671675264, 14680061056, 14688447616, 14696835968, + 14705228416, 14713616768, 14722003328, 14730392192, 14738784128, + 14747172736, 14755561088, 14763947648, 14772336512, 14780725376, + 14789110144, 14797499776, 14805892736, 14814276992, 14822670208, + 14831056256, 14839444352, 14847836032, 14856222848, 14864612992, + 14872997504, 14881388672, 14889775744, 14898165376, 14906553472, + 14914944896, 14923329664, 14931721856, 14940109696, 14948497024, + 14956887424, 14965276544, 14973663616, 14982053248, 14990439808, + 14998830976, 15007216768, 15015605888, 15023995264, 15032385152, + 15040768384, 15049154944, 15057549184, 15065939072, 15074328448, + 15082715008, 15091104128, 15099493504, 15107879296, 15116269184, + 15124659584, 15133042304, 15141431936, 15149824384, 15158214272, + 15166602368, 15174991232, 15183378304, 15191760512, 15200154496, + 15208542592, 15216931712, 15225323392, 15233708416, 15242098048, + 15250489216, 15258875264, 15267265408, 15275654528, 15284043136, + 15292431488, 15300819584, 15309208192, 15317596544, 15325986176, + 15334374784, 15342763648, 15351151744, 15359540608, 15367929728, + 15376318336, 15384706432, 15393092992, 15401481856, 15409869952, + 15418258816, 15426649984, 15435037568, 15443425664, 15451815296, + 15460203392, 15468589184, 15476979328, 15485369216, 15493755776, + 15502146944, 15510534272, 15518924416, 15527311232, 15535699072, + 15544089472, 15552478336, 15560866688, 15569254528, 15577642624, + 15586031488, 15594419072, 15602809472, 15611199104, 15619586432, + 15627975296, 15636364928, 15644753792, 15653141888, 15661529216, + 15669918848, 15678305152, 15686696576, 15695083136, 15703474048, + 15711861632, 15720251264, 15728636288, 15737027456, 15745417088, + 15753804928, 15762194048, 15770582656, 15778971008, 15787358336, + 15795747712, 15804132224, 15812523392, 15820909696, 15829300096, + 15837691264, 15846071936, 15854466944, 15862855808, 15871244672, + 15879634816, 15888020608, 15896409728, 15904799104, 15913185152, + 15921577088, 15929966464, 15938354816, 15946743424, 15955129472, + 15963519872, 15971907968, 15980296064, 15988684928, 15997073024, + 16005460864, 16013851264, 16022241152, 16030629248, 16039012736, + 16047406976, 16055794816, 16064181376, 16072571264, 16080957824, + 16089346688, 16097737856, 16106125184, 16114514816, 16122904192, + 16131292544, 16139678848, 16148066944, 16156453504, 16164839552, + 16173236096, 16181623424, 16190012032, 16198401152, 16206790528, + 16215177344, 16223567744, 16231956352, 16240344704, 16248731008, + 16257117824, 16265504384, 16273898624, 16282281856, 16290668672, + 16299064192, 16307449216, 16315842176, 16324230016, 16332613504, + 16341006464, 16349394304, 16357783168, 16366172288, 16374561664, + 16382951296, 16391337856, 16399726208, 16408116352, 16416505472, + 16424892032, 16433282176, 16441668224, 16450058624, 16458448768, + 16466836864, 16475224448, 16483613056, 16492001408, 16500391808, + 16508779648, 16517166976, 16525555328, 16533944192, 16542330752, + 16550719616, 16559110528, 16567497088, 16575888512, 16584274816, + 16592665472, 16601051008, 16609442944, 16617832064, 16626218624, + 16634607488, 16642996096, 16651385728, 16659773824, 16668163712, + 16676552576, 16684938112, 16693328768, 16701718144, 16710095488, + 16718492288, 16726883968, 16735272832, 16743661184, 16752049792, + 16760436608, 16768827008, 16777214336, 16785599104, 16793992832, + 16802381696, 16810768768, 16819151744, 16827542656, 16835934848, + 16844323712, 16852711552, 16861101952, 16869489536, 16877876864, + 16886265728, 16894653056, 16903044736, 16911431296, 16919821696, + 16928207488, 16936592768, 16944987776, 16953375616, 16961763968, + 16970152832, 16978540928, 16986929536, 16995319168, 17003704448, + 17012096896, 17020481152, 17028870784, 17037262208, 17045649536, + 17054039936, 17062426496, 17070814336, 17079205504, 17087592064, + 17095978112, 17104369024, 17112759424, 17121147776, 17129536384, + 17137926016, 17146314368, 17154700928, 17163089792, 17171480192, + 17179864192, 17188256896, 17196644992, 17205033856, 17213423488, + 17221811072, 17230198912, 17238588032, 17246976896, 17255360384, + 17263754624, 17272143232, 17280530048, 17288918912, 17297309312, + 17305696384, 17314085504, 17322475136, 17330863744, 17339252096, + 17347640192, 17356026496, 17364413824, 17372796544, 17381190016, + 17389583488, 17397972608, 17406360704, 17414748544, 17423135872, + 17431527296, 17439915904, 17448303232, 17456691584, 17465081728, + 17473468288, 17481857408, 17490247552, 17498635904, 17507022464, + 17515409024, 17523801728, 17532189824, 17540577664, 17548966016, + 17557353344, 17565741184, 17574131584, 17582519168, 17590907008, + 17599296128, 17607687808, 17616076672, 17624455808, 17632852352, + 17641238656, 17649630848, 17658018944, 17666403968, 17674794112, + 17683178368, 17691573376, 17699962496, 17708350592, 17716739968, + 17725126528, 17733517184, 17741898112, 17750293888, 17758673024, + 17767070336, 17775458432, 17783848832, 17792236928, 17800625536, + 17809012352, 17817402752, 17825785984, 17834178944, 17842563968, + 17850955648, 17859344512, 17867732864, 17876119424, 17884511872, + 17892900224, 17901287296, 17909677696, 17918058112, 17926451072, + 17934843776, 17943230848, 17951609216, 17960008576, 17968397696, + 17976784256, 17985175424, 17993564032, 18001952128, 18010339712, + 18018728576, 18027116672, 18035503232, 18043894144, 18052283264, + 18060672128, 18069056384, 18077449856, 18085837184, 18094225792, + 18102613376, 18111004544, 18119388544, 18127781248, 18136170368, + 18144558976, 18152947328, 18161336192, 18169724288, 18178108544, + 18186498944, 18194886784, 18203275648, 18211666048, 18220048768, + 18228444544, 18236833408, 18245220736 +]; diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js index bec1284f6..edff47e63 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js @@ -7,184 +7,192 @@ var Keccak = require('./keccak'); var util = require('./util'); +var ethUtil = require('ethereumjs-util'); // 32-bit unsigned modulo -function mod32(x, n) -{ - return (x>>>0) % (n>>>0); +function mod32(x, n) { + return (x >>> 0) % (n >>> 0); } -function fnv(x, y) -{ - // js integer multiply by 0x01000193 will lose precision - return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y; +function fnv(x, y) { + // js integer multiply by 0x01000193 will lose precision + return ((x * 0x01000000 | 0) + (x * 0x193 | 0)) ^ y; } -function computeCache(params, seedWords) -{ - var cache = new Uint32Array(params.cacheSize >> 2); - var cacheNodeCount = params.cacheSize >> 6; +function computeCache(params, seedWords) { + var cache = new Uint32Array(params.cacheSize >> 2); + var cacheNodeCount = params.cacheSize >> 6; - // Initialize cache - var keccak = new Keccak(); - keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length); - for (var n = 1; n < cacheNodeCount; ++n) - { - keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16); - } - - var tmp = new Uint32Array(16); - - // Do randmemohash passes - for (var r = 0; r < params.cacheRounds; ++r) - { - for (var n = 0; n < cacheNodeCount; ++n) - { - var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4; - var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4; - - for (var w = 0; w < 16; w=(w+1)|0) - { - tmp[w] = cache[p0 | w] ^ cache[p1 | w]; - } - - keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length); - } - } - return cache; + // Initialize cache + var keccak = new Keccak(); + keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length); + for (var n = 1; n < cacheNodeCount; ++n) { + keccak.digestWords(cache, n << 4, 16, cache, (n - 1) << 4, 16); + } + + var tmp = new Uint32Array(16); + + // Do randmemohash passes + for (var r = 0; r < params.cacheRounds; ++r) { + for (var n = 0; n < cacheNodeCount; ++n) { + var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4; + var p1 = mod32(cache[n << 4 | 0], cacheNodeCount) << 4; + + for (var w = 0; w < 16; w = (w + 1) | 0) { + tmp[w] = cache[p0 | w] ^ cache[p1 | w]; + } + + keccak.digestWords(cache, n << 4, 16, tmp, 0, tmp.length); + } + } + return cache; } -function computeDagNode(o_node, params, cache, keccak, nodeIndex) -{ - var cacheNodeCount = params.cacheSize >> 6; - var dagParents = params.dagParents; - - var c = (nodeIndex % cacheNodeCount) << 4; - var mix = o_node; - for (var w = 0; w < 16; ++w) - { - mix[w] = cache[c|w]; - } - mix[0] ^= nodeIndex; - keccak.digestWords(mix, 0, 16, mix, 0, 16); - - for (var p = 0; p < dagParents; ++p) - { - // compute cache node (word) index - c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4; - - for (var w = 0; w < 16; ++w) - { - mix[w] = fnv(mix[w], cache[c|w]); - } - } - - keccak.digestWords(mix, 0, 16, mix, 0, 16); +function computeDagNode(o_node, params, cache, keccak, nodeIndex) { + var cacheNodeCount = params.cacheSize >> 6; + var dagParents = params.dagParents; + + var c = (nodeIndex % cacheNodeCount) << 4; + var mix = o_node; + for (var w = 0; w < 16; ++w) { + mix[w] = cache[c | w]; + } + mix[0] ^= nodeIndex; + keccak.digestWords(mix, 0, 16, mix, 0, 16); + + for (var p = 0; p < dagParents; ++p) { + // compute cache node (word) index + c = mod32(fnv(nodeIndex ^ p, mix[p & 15]), cacheNodeCount) << 4; + + for (var w = 0; w < 16; ++w) { + mix[w] = fnv(mix[w], cache[c | w]); + } + } + + keccak.digestWords(mix, 0, 16, mix, 0, 16); } -function computeHashInner(mix, params, cache, keccak, tempNode) -{ - var mixParents = params.mixParents|0; - var mixWordCount = params.mixSize >> 2; - var mixNodeCount = mixWordCount >> 4; - var dagPageCount = (params.dagSize / params.mixSize) >> 0; - - // grab initial first word - var s0 = mix[0]; - - // initialise mix from initial 64 bytes - for (var w = 16; w < mixWordCount; ++w) - { - mix[w] = mix[w & 15]; - } - - for (var a = 0; a < mixParents; ++a) - { - var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount); - var d = (p * mixNodeCount)|0; - - for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16) - { - computeDagNode(tempNode, params, cache, keccak, (d + n)|0); - - for (var v = 0; v < 16; ++v) - { - mix[w|v] = fnv(mix[w|v], tempNode[v]); - } - } - } +function computeHashInner(mix, params, cache, keccak, tempNode) { + var mixParents = params.mixParents | 0; + var mixWordCount = params.mixSize >> 2; + var mixNodeCount = mixWordCount >> 4; + var dagPageCount = (params.dagSize / params.mixSize) >> 0; + + // grab initial first word + var s0 = mix[0]; + + // initialise mix from initial 64 bytes + for (var w = 16; w < mixWordCount; ++w) { + mix[w] = mix[w & 15]; + } + + for (var a = 0; a < mixParents; ++a) { + var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount - 1)]), dagPageCount); + var d = (p * mixNodeCount) | 0; + + for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16) { + computeDagNode(tempNode, params, cache, keccak, (d + n) | 0); + + for (var v = 0; v < 16; ++v) { + mix[w | v] = fnv(mix[w | v], tempNode[v]); + } + } + } } -function convertSeed(seed) -{ - // todo, reconcile with spec, byte ordering? - // todo, big-endian conversion - var newSeed = util.toWords(seed); - if (newSeed === null) - throw Error("Invalid seed '" + seed + "'"); - return newSeed; +function convertSeed(seed) { + // todo, reconcile with spec, byte ordering? + // todo, big-endian conversion + var newSeed = util.toWords(seed); + if (newSeed === null) + throw Error("Invalid seed '" + seed + "'"); + return newSeed; } -exports.defaultParams = function() -{ - return { - cacheSize: 1048384, - cacheRounds: 3, - dagSize: 1073739904, - dagParents: 256, - mixSize: 128, - mixParents: 64, - }; +var params = exports.params = { + REVISION: 23, + DATASET_BYTES_INIT: 1073741824, + DATASET_BYTES_GROWTH: 8388608, + CACHE_BYTES_INIT: 1073741824, + CACHE_BYTES_GROWTH: 131072, + EPOCH_LENGTH: 30000, + MIX_BYTES: 128, + HASH_BYTES: 64, + DATASET_PARENTS: 256, + CACHE_ROUNDS: 3, + ACCESSES: 64 }; -exports.Ethash = function(params, seed) -{ - // precompute cache and related values - seed = convertSeed(seed); - var cache = computeCache(params, seed); - - // preallocate buffers/etc - var initBuf = new ArrayBuffer(96); - var initBytes = new Uint8Array(initBuf); - var initWords = new Uint32Array(initBuf); - var mixWords = new Uint32Array(params.mixSize / 4); - var tempNode = new Uint32Array(16); - var keccak = new Keccak(); - - var retWords = new Uint32Array(8); - var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only - - this.hash = function(header, nonce) - { - // compute initial hash - initBytes.set(header, 0); - initBytes.set(nonce, 32); - keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4); - - // compute mix - for (var i = 0; i != 16; ++i) - { - mixWords[i] = initWords[i]; - } - computeHashInner(mixWords, params, cache, keccak, tempNode); - - // compress mix and append to initWords - for (var i = 0; i != mixWords.length; i += 4) - { - initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]); - } - - // final Keccak hashes - keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix) - return retBytes; - }; - - this.cacheDigest = function() - { - return keccak.digest(32, new Uint8Array(cache.buffer)); - }; +var cache_sizes = require('./cache_sizes'); +var dag_sizes = require('./dag_sizes'); + +exports.calcSeed = function(blockNum) { + var epoch; + + var seed = new Uint8Array(32); + + if (blockNum > cache_sizes.length * params.EPOCH_LENGTH) { + return new Error('Time to upgrade to POS!!!'); + } else { + epoch = Math.floor(blockNum / params.EPOCH_LENGTH); + + for (var i = 0; i < epoch; i++) { + seed = ethUtil.sha3(new Buffer(seed)); + } + return seed; + } }; +exports.defaultParams = function() { + return { + cacheSize: 1048384, + cacheRounds: 3, + dagSize: 1073739904, + dagParents: 256, + mixSize: 128, + mixParents: 64 + }; +}; +exports.Ethash = function(params, seed) { + // precompute cache and related values + // seed = convertSeed(seed); + var cache = computeCache(params, seed); + // preallocate buffers/etc + var initBuf = new ArrayBuffer(96); + var initBytes = new Uint8Array(initBuf); + var initWords = new Uint32Array(initBuf); + var mixWords = new Uint32Array(params.mixSize / 4); + var tempNode = new Uint32Array(16); + var keccak = new Keccak(); + var retWords = new Uint32Array(8); + var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only + + this.hash = function(header, nonce) { + // compute initial hash + initBytes.set(header, 0); + initBytes.set(nonce, 32); + keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length / 4); + + // compute mix + for (var i = 0; i !== 16; ++i) { + mixWords[i] = initWords[i]; + } + computeHashInner(mixWords, params, cache, keccak, tempNode); + + // compress mix and append to initWords + for (var i = 0; i !== mixWords.length; i += 4) { + initWords[16 + i / 4] = fnv(fnv(fnv(mixWords[i], mixWords[i + 1]), mixWords[i + 2]), mixWords[i + 3]); + } + + // final Keccak hashes + keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix) + return retBytes; + }; + + this.cacheDigest = function() { + return keccak.digest(32, new Uint8Array(cache.buffer)); + }; +}; diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/package.json b/Godeps/_workspace/src/github.com/ethereum/ethash/js/package.json new file mode 100644 index 000000000..08a14d479 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/package.json @@ -0,0 +1,21 @@ +{ + "name": "ethash.js", + "version": "0.0.1", + "description": "", + "main": "ethash.js", + "scripts": { + "test": "node ./test/test.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/ethereum/ethash/tree/master/js" + }, + "keywords": [ + "ethereum" + ], + "author": "", + "license": "mit", + "devDependencies": { + "ethereum-tests": "0.0.5" + } +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/test/seedHash.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test/seedHash.js new file mode 100644 index 000000000..a3666a9ed --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test/seedHash.js @@ -0,0 +1,48 @@ +var tape = require('tape'); +const ethash = require('../ethash.js'); + +tape('seed hash', function(t) { + + t.test('seed should match TRUTH', function(st) { + const seed = '290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563'; + const blockNum = 30000; + + var r = new Buffer(ethash.calcSeed(blockNum)); + st.equal(r.toString('hex'), seed); + + st.end(); + }); + + t.test('seed should match TRUTH2', function(st) { + const seed = '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9'; + const blockNum = 60000; + + var r = new Buffer(ethash.calcSeed(blockNum)); + st.equal(r.toString('hex'), seed); + + st.end(); + }); + + t.test('seed should match TRUTH3', function(st) { + const seed = '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9'; + const blockNum = 60700; + + var r = new Buffer(ethash.calcSeed(blockNum)); + st.equal(r.toString('hex'), seed); + + st.end(); + }); + + t.test('randomized tests', function(st) { + for (var i = 0; i < 100; i++) { + var x = Math.floor(ethash.params.EPOCH_LENGTH * 2048 * Math.random()); + st.equal(ethash.calcSeed(x).toString('hex'), ethash.calcSeed(Math.floor(x / ethash.params.EPOCH_LENGTH) * ethash.params.EPOCH_LENGTH ).toString('hex')); + } + st.end(); + }); + // '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9' + // [7:13:32 PM] Matthew Wampler-Doty: >>> x = randint(0,700000) + // + // >>> pyethash.get_seedhash(x).encode('hex') == pyethash.get_seedhash((x // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH).encode('hex') + +}); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test/test.js similarity index 85% rename from Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js rename to Godeps/_workspace/src/github.com/ethereum/ethash/js/test/test.js index 7ebb733ff..edffa268f 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test/test.js @@ -4,9 +4,9 @@ /*jslint node: true, shadow:true */ "use strict"; -var ethash = require('./ethash'); -var util = require('./util'); -var Keccak = require('./keccak'); +var ethash = require('../ethash'); +var util = require('../util'); +var Keccak = require('../keccak'); // sanity check hash functions var src = util.stringToBytes(""); @@ -31,23 +31,22 @@ var ethashParams = ethash.defaultParams(); var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466") var startTime = new Date().getTime(); var hasher = new ethash.Ethash(ethashParams, seed); -console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms"); +console.log('Ethash startup took: ' + (new Date().getTime() - startTime) + "ms"); console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest())); var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; if (testHexString != util.bytesToHexString(util.hexStringToBytes(testHexString))) - throw Error("bytesToHexString or hexStringToBytes broken"); + throw Error("bytesToHexString or hexStringToBytes broken"); + - var header = util.hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); var nonce = util.hexStringToBytes("0000000000000000"); var hash; startTime = new Date().getTime(); var trials = 10; -for (var i = 0; i < trials; ++i) -{ - hash = hasher.hash(header, nonce); +for (var i = 0; i < trials; ++i) { + hash = hasher.hash(header, nonce); } -console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms"); +console.log("Light client hashes averaged: " + (new Date().getTime() - startTime) / trials + "ms"); console.log("Hash = " + util.bytesToHexString(hash)); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py b/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py index 29d6ad6d2..eedd337ae 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py @@ -25,9 +25,9 @@ setup ( author = "Matthew Wampler-Doty", author_email = "matthew.wampler.doty@gmail.com", license = 'GPL', - version = '23', + version = '23.1', url = 'https://github.com/ethereum/ethash', - download_url = 'https://github.com/ethereum/ethash/tarball/v23', + download_url = 'https://github.com/ethereum/ethash/tarball/v23.1', description = 'Python wrappers for ethash, the ethereum proof of work hashing function', ext_modules = [pyethash], ) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h index 3b747b3ea..cf52ae4f8 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h @@ -48,7 +48,7 @@ extern "C" { // Sow[i*HashBytes]; j++]]]][[2]][[1]] -static const size_t dag_sizes[2048] = { +static const uint64_t dag_sizes[2048] = { 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, @@ -477,7 +477,7 @@ static const size_t dag_sizes[2048] = { // While[! PrimeQ[i], i--]; // Sow[i*HashBytes]; j++]]]][[2]][[1]] -const size_t cache_sizes[2048] = { +const uint64_t cache_sizes[2048] = { 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h index a7159de65..cc3d634d0 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h @@ -43,8 +43,8 @@ extern "C" { #endif typedef struct ethash_params { - size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). - size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)). + uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). + uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)). } ethash_params; typedef struct ethash_return_value { @@ -52,45 +52,52 @@ typedef struct ethash_return_value { uint8_t mix_hash[32]; } ethash_return_value; -size_t ethash_get_datasize(const uint32_t block_number); -size_t ethash_get_cachesize(const uint32_t block_number); +uint64_t ethash_get_datasize(const uint32_t block_number); +uint64_t ethash_get_cachesize(const uint32_t block_number); -// initialize the parameters -static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) { +// Initialize the Parameters +static inline int ethash_params_init(ethash_params *params, const uint32_t block_number) { params->full_size = ethash_get_datasize(block_number); + if (params->full_size == 0) + return 0; + params->cache_size = ethash_get_cachesize(block_number); + if (params->cache_size == 0) + return 0; + + return 1; } typedef struct ethash_cache { void *mem; } ethash_cache; -void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); -void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); -void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); -void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); +int ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); +int ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); +int ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); +int ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); -static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { +static inline int ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; - ethash_mkcache(&c, params, seed); + return ethash_mkcache(&c, params, seed); } -static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { +static inline int ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void *) cache; - ethash_light(ret, &c, params, header_hash, nonce); + return ethash_light(ret, &c, params, header_hash, nonce); } -static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { +static inline int ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void *) cache; - ethash_compute_full_data(full, params, &c); + return ethash_compute_full_data(full, params, &c); } -static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { - ethash_full(ret, full, params, header_hash, nonce); +static inline int ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { + return ethash_full(ret, full, params, header_hash, nonce); } // Returns if hash is less than or equal to difficulty diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c index 0a7e767e7..c8748408a 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c @@ -20,7 +20,6 @@ * @date 2015 */ -#include #include #include #include "ethash.h" @@ -29,6 +28,9 @@ #include "internal.h" #include "data_sizes.h" +// Inline assembly doesn't work +#define ENABLE_SSE 0 + #ifdef WITH_CRYPTOPP #include "sha3_cryptopp.h" @@ -37,24 +39,29 @@ #include "sha3.h" #endif // WITH_CRYPTOPP -size_t ethash_get_datasize(const uint32_t block_number) { - assert(block_number / EPOCH_LENGTH < 2048); +uint64_t ethash_get_datasize(const uint32_t block_number) { + if (block_number / EPOCH_LENGTH >= 2048) + return 0; return dag_sizes[block_number / EPOCH_LENGTH]; } -size_t ethash_get_cachesize(const uint32_t block_number) { - assert(block_number / EPOCH_LENGTH < 2048); +uint64_t ethash_get_cachesize(const uint32_t block_number) { + if (block_number / EPOCH_LENGTH >= 2048) + return 0; return cache_sizes[block_number / EPOCH_LENGTH]; } // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf // SeqMemoHash(s, R, N) -void static ethash_compute_cache_nodes( +int static ethash_compute_cache_nodes( node *const nodes, ethash_params const *params, const uint8_t seed[32]) { - assert((params->cache_size % sizeof(node)) == 0); + + if ((params->cache_size % sizeof(node)) != 0) + return 0; + uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); SHA3_512(nodes[0].bytes, seed, 32); @@ -82,22 +89,27 @@ void static ethash_compute_cache_nodes( nodes->words[w] = fix_endian32(nodes->words[w]); } #endif + + return 1; } -void ethash_mkcache( +int ethash_mkcache( ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]) { node *nodes = (node *) cache->mem; - ethash_compute_cache_nodes(nodes, params, seed); + return ethash_compute_cache_nodes(nodes, params, seed); } -void ethash_calculate_dag_item( +int ethash_calculate_dag_item( node *const ret, - const unsigned node_index, + const uint64_t node_index, const struct ethash_params *params, const struct ethash_cache *cache) { + if (params->cache_size % sizeof(node) != 0) + return 0; + uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); node const *cache_nodes = (node const *) cache->mem; node const *init = &cache_nodes[node_index % num_parent_nodes]; @@ -145,23 +157,58 @@ void ethash_calculate_dag_item( } SHA3_512(ret->bytes, ret->bytes, sizeof(node)); + return 1; } -void ethash_compute_full_data( +int ethash_compute_full_data( void *mem, ethash_params const *params, ethash_cache const *cache) { - assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0); - assert((params->full_size % sizeof(node)) == 0); + + if ((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) != 0) + return 0; + + if ((params->full_size % sizeof(node)) != 0) + return 0; + node *full_nodes = mem; // now compute full nodes - for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) { + for (uint64_t n = 0; n != (params->full_size / sizeof(node)); ++n) { ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); } + return 1; } -static void ethash_hash( +int ethash_compute_full_data_section( + void *mem, + ethash_params const *params, + ethash_cache const *cache, + uint64_t const start, + uint64_t const end) { + + if ((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) != 0) + return 0; + + if ((params->full_size % sizeof(node)) != 0) + return 0; + + if (end >= params->full_size) + return 0; + + if (start >= end) + return 0; + + node *full_nodes = mem; + + // now compute full nodes + for (uint64_t n = start; n != end; ++n) { + ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); + } + return 1; +} + +static int ethash_hash( ethash_return_value *ret, node const *full_nodes, ethash_cache const *cache, @@ -169,10 +216,10 @@ static void ethash_hash( const uint8_t header_hash[32], const uint64_t nonce) { - assert((params->full_size % MIX_WORDS) == 0); + if ((params->full_size % MIX_WORDS) != 0) + return 0; // pack hash and nonce together into first 40 bytes of s_mix - assert(sizeof(node) * 8 == 512); node s_mix[MIX_NODES + 1]; memcpy(s_mix[0].bytes, header_hash, 32); @@ -254,6 +301,7 @@ static void ethash_hash( memcpy(ret->mix_hash, mix->bytes, 32); // final Keccak hash SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) + return 1; } void ethash_quick_hash( @@ -291,10 +339,10 @@ int ethash_quick_check_difficulty( return ethash_check_difficulty(return_hash, difficulty); } -void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { - ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); +int ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { + return ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); } -void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { - ethash_hash(ret, NULL, cache, params, previous_hash, nonce); +int ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { + return ethash_hash(ret, NULL, cache, params, previous_hash, nonce); } \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h index ddd06e8f4..dc79b35b4 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h @@ -30,9 +30,9 @@ typedef union node { } node; -void ethash_calculate_dag_item( +int ethash_calculate_dag_item( node *const ret, - const unsigned node_index, + const uint64_t node_index, ethash_params const *params, ethash_cache const *cache ); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c index 359735998..6d0a40ad0 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c @@ -58,7 +58,7 @@ mkcache_bytes(PyObject *self, PyObject *args) { } ethash_params params; - params.cache_size = (size_t) cache_size; + params.cache_size = (uint64_t) cache_size; ethash_cache cache; cache.mem = malloc(cache_size); ethash_mkcache(&cache, ¶ms, (uint8_t *) seed); @@ -92,8 +92,8 @@ calc_dataset_bytes(PyObject *self, PyObject *args) { } ethash_params params; - params.cache_size = (size_t) cache_size; - params.full_size = (size_t) full_size; + params.cache_size = (uint64_t) cache_size; + params.full_size = (uint64_t) full_size; ethash_cache cache; cache.mem = (void *) cache_bytes; void *mem = malloc(params.full_size); @@ -138,8 +138,8 @@ hashimoto_light(PyObject *self, PyObject *args) { ethash_return_value out; ethash_params params; - params.cache_size = (size_t) cache_size; - params.full_size = (size_t) full_size; + params.cache_size = (uint64_t) cache_size; + params.full_size = (uint64_t) full_size; ethash_cache cache; cache.mem = (void *) cache_bytes; ethash_light(&out, &cache, ¶ms, (uint8_t *) header, nonce); @@ -175,7 +175,7 @@ hashimoto_full(PyObject *self, PyObject *args) { ethash_return_value out; ethash_params params; - params.full_size = (size_t) full_size; + params.full_size = (uint64_t) full_size; ethash_full(&out, (void *) full_bytes, ¶ms, (uint8_t *) header, nonce); return Py_BuildValue("{s:s#, s:s#}", "mix digest", out.mix_hash, 32, @@ -216,7 +216,7 @@ mine(PyObject *self, PyObject *args) { ethash_return_value out; ethash_params params; - params.full_size = (size_t) full_size; + params.full_size = (uint64_t) full_size; // TODO: Multi threading? do { diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp index 21cb251fc..8c854ecbd 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp @@ -17,7 +17,7 @@ #include #include -std::string bytesToHexString(const uint8_t *str, const size_t s) { +std::string bytesToHexString(const uint8_t *str, const uint32_t s) { std::ostringstream ret; for (int i = 0; i < s; ++i) @@ -80,9 +80,11 @@ BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) { BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) { ethash_params params; - ethash_params_init(¶ms, 0); - const uint32_t expected_full_size = 1073739904; - const uint32_t expected_cache_size = 16776896; + BOOST_REQUIRE_MESSAGE(ethash_params_init(¶ms, 0), + "Params could not be initialized"); + const uint32_t + expected_full_size = 1073739904, + expected_cache_size = 16776896; BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size, "\nexpected: " << expected_cache_size << "\n" << "actual: " << params.full_size << "\n"); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh index fd3508609..71e53d978 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh @@ -14,11 +14,8 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" echo -e "\n################# Testing JS ##################" # TODO: Use mocha and real testing tools instead of rolling our own cd $TEST_DIR/../js -if [ -x "$(which nodejs)" ] ; then - nodejs test.js -fi -if [ -x "$(which node)" ] ; then - node test.js +if [ -x "$(which npm)" ] ; then + npm test fi echo -e "\n################# Testing C ##################" From 01ff0b3176e6d83dcc5e6716f04301de71e3fc9e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Mar 2015 11:40:46 +0100 Subject: [PATCH 49/78] fixed ethash --- Godeps/Godeps.json | 4 ++-- Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 0cdb4b026..b97dec91f 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -22,8 +22,8 @@ }, { "ImportPath": "github.com/ethereum/ethash", - "Comment": "v23.1-25-gc0429f2", - "Rev": "c0429f268b62e2238b684d4b5495f8ff24115424" + "Comment": "v23.1-26-g934bb4f", + "Rev": "934bb4f5060ab69d96fb6eba4b9a57facc4e160b" }, { "ImportPath": "github.com/ethereum/serpent-go", diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go index 8c325d25d..3c24fd239 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go @@ -85,7 +85,7 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) (*Params Epoch: blockNum / epochLength, } C.ethash_params_init(paramsAndCache.params, C.uint32_t(uint32(blockNum))) - paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size) + paramsAndCache.cache.mem = C.malloc(C.size_t(paramsAndCache.params.cache_size)) seedHash, err := GetSeedHash(blockNum) if err != nil { @@ -118,7 +118,7 @@ func (pow *Ethash) UpdateCache(force bool) error { func makeDAG(p *ParamsAndCache) *DAG { d := &DAG{ - dag: C.malloc(p.params.full_size), + dag: C.malloc(C.size_t(p.params.full_size)), file: false, paramsAndCache: p, } From 50661f0e683b4975894a0e8fe16024724adef72d Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 22:46:54 +0000 Subject: [PATCH 50/78] peer suspension to disallow reconnect after disconnect on fatal error for set period (PeerSuspensionInterval) --- blockpool/blockpool.go | 17 +++++++---- blockpool/blockpool_test.go | 6 ++-- blockpool/blockpool_util_test.go | 30 +++++++++++-------- blockpool/config_test.go | 4 ++- blockpool/errors_test.go | 33 ++++++++++++++++++++- blockpool/peers.go | 49 +++++++++++++++++++++++++------- blockpool/test/hash_pool.go | 17 +++++------ eth/protocol.go | 13 ++++++--- 8 files changed, 125 insertions(+), 44 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index c5af481a7..ef619b27b 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -33,7 +33,8 @@ var ( // timeout interval: max time allowed for peer without sending a block blocksTimeout = 60 * time.Second // - idleBestPeerTimeout = 120 * time.Second + idleBestPeerTimeout = 120 * time.Second + peerSuspensionInterval = 300 * time.Second ) // config embedded in components, by default fall back to constants @@ -48,6 +49,7 @@ type Config struct { BlockHashesTimeout time.Duration BlocksTimeout time.Duration IdleBestPeerTimeout time.Duration + PeerSuspensionInterval time.Duration } // blockpool errors @@ -96,6 +98,9 @@ func (self *Config) init() { if self.IdleBestPeerTimeout == 0 { self.IdleBestPeerTimeout = idleBestPeerTimeout } + if self.PeerSuspensionInterval == 0 { + self.PeerSuspensionInterval = peerSuspensionInterval + } } // node is the basic unit of the internal model of block chain/tree in the blockpool @@ -188,9 +193,10 @@ func (self *BlockPool) Start() { Errors: errorToString, Level: severity, }, - peers: make(map[string]*peer), - status: self.status, - bp: self, + peers: make(map[string]*peer), + blacklist: make(map[string]time.Time), + status: self.status, + bp: self, } timer := time.NewTicker(3 * time.Second) go func() { @@ -267,7 +273,8 @@ func (self *BlockPool) AddPeer( requestBlocks func([]common.Hash) error, peerError func(*errs.Error), -) (best bool) { +) (best bool, suspended bool) { + return self.peers.addPeer(td, currentBlockHash, peerId, requestBlockHashes, requestBlocks, peerError) } diff --git a/blockpool/blockpool_test.go b/blockpool/blockpool_test.go index 411779057..d8271886f 100644 --- a/blockpool/blockpool_test.go +++ b/blockpool/blockpool_test.go @@ -5,8 +5,8 @@ import ( "time" "github.com/ethereum/go-ethereum/blockpool/test" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" ) func TestPeerWithKnownBlock(t *testing.T) { @@ -69,8 +69,8 @@ func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) { hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3}) peer1.waitBlocksRequests(3) blockPool.AddBlock(&types.Block{ - HeaderHash: common.Bytes(hashes[1]), - ParentHeaderHash: common.Bytes(hashes[0]), + HeaderHash: common.Hash(hashes[1]), + ParentHeaderHash: common.Hash(hashes[0]), Td: common.Big3, }, "peer1") diff --git a/blockpool/blockpool_util_test.go b/blockpool/blockpool_util_test.go index 9ac996bca..5ba92066c 100644 --- a/blockpool/blockpool_util_test.go +++ b/blockpool/blockpool_util_test.go @@ -8,9 +8,9 @@ import ( "time" "github.com/ethereum/go-ethereum/blockpool/test" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/pow" ) @@ -63,10 +63,10 @@ func (self *blockPoolTester) Errorf(format string, params ...interface{}) { // blockPoolTester implements the 3 callbacks needed by the blockPool: // hasBlock, insetChain, verifyPoW -func (self *blockPoolTester) hasBlock(block []byte) (ok bool) { +func (self *blockPoolTester) hasBlock(block common.Hash) (ok bool) { self.lock.RLock() defer self.lock.RUnlock() - indexes := self.hashPool.HashesToIndexes([][]byte{block}) + indexes := self.hashPool.HashesToIndexes([]common.Hash{block}) i := indexes[0] _, ok = self.blockChain[i] fmt.Printf("has block %v (%x...): %v\n", i, block[0:4], ok) @@ -80,13 +80,13 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error { var children, refChildren []int var ok bool for _, block := range blocks { - child = self.hashPool.HashesToIndexes([][]byte{block.Hash()})[0] + child = self.hashPool.HashesToIndexes([]common.Hash{block.Hash()})[0] _, ok = self.blockChain[child] if ok { fmt.Printf("block %v already in blockchain\n", child) continue // already in chain } - parent = self.hashPool.HashesToIndexes([][]byte{block.ParentHeaderHash})[0] + parent = self.hashPool.HashesToIndexes([]common.Hash{block.ParentHeaderHash})[0] children, ok = self.blockChain[parent] if !ok { return fmt.Errorf("parent %v not in blockchain ", parent) @@ -274,9 +274,10 @@ func (self *blockPoolTester) initRefBlockChain(n int) { // peerTester functions that mimic protocol calls to the blockpool // registers the peer with the blockPool -func (self *peerTester) AddPeer() bool { +func (self *peerTester) AddPeer() (best bool) { hash := self.hashPool.IndexesToHashes([]int{self.currentBlock})[0] - return self.blockPool.AddPeer(big.NewInt(int64(self.td)), hash, self.id, self.requestBlockHashes, self.requestBlocks, self.peerError) + best, _ = self.blockPool.AddPeer(big.NewInt(int64(self.td)), hash, self.id, self.requestBlockHashes, self.requestBlocks, self.peerError) + return } // peer sends blockhashes if and when gets a request @@ -291,7 +292,7 @@ func (self *peerTester) sendBlockHashes(indexes ...int) { fmt.Printf("adding block hashes %v\n", indexes) hashes := self.hashPool.IndexesToHashes(indexes) i := 1 - next := func() (hash []byte, ok bool) { + next := func() (hash common.Hash, ok bool) { if i < len(hashes) { hash = hashes[i] ok = true @@ -315,15 +316,15 @@ func (self *peerTester) sendBlocks(indexes ...int) { hashes := self.hashPool.IndexesToHashes(indexes) for i := 1; i < len(hashes); i++ { fmt.Printf("adding block %v %x\n", indexes[i], hashes[i][:4]) - self.blockPool.AddBlock(&types.Block{HeaderHash: common.Bytes(hashes[i]), ParentHeaderHash: common.Bytes(hashes[i-1])}, self.id) + self.blockPool.AddBlock(&types.Block{HeaderHash: hashes[i], ParentHeaderHash: hashes[i-1]}, self.id) } } // peer callbacks // -1 is special: not found (a hash never seen) // records block hashes requests by the blockPool -func (self *peerTester) requestBlockHashes(hash []byte) error { - indexes := self.hashPool.HashesToIndexes([][]byte{hash}) +func (self *peerTester) requestBlockHashes(hash common.Hash) error { + indexes := self.hashPool.HashesToIndexes([]common.Hash{hash}) fmt.Printf("[%s] block hash request %v %x\n", self.id, indexes[0], hash[:4]) self.lock.Lock() defer self.lock.Unlock() @@ -332,7 +333,7 @@ func (self *peerTester) requestBlockHashes(hash []byte) error { } // records block requests by the blockPool -func (self *peerTester) requestBlocks(hashes [][]byte) error { +func (self *peerTester) requestBlocks(hashes []common.Hash) error { indexes := self.hashPool.HashesToIndexes(hashes) fmt.Printf("blocks request %v %x...\n", indexes, hashes[0][:4]) self.bt.reqlock.Lock() @@ -347,4 +348,9 @@ func (self *peerTester) requestBlocks(hashes [][]byte) error { // records the error codes of all the peerErrors found the blockPool func (self *peerTester) peerError(err *errs.Error) { self.peerErrors = append(self.peerErrors, err.Code) + fmt.Printf("Error %v on peer %v\n", err, self.id) + if err.Fatal() { + fmt.Printf("Error %v is fatal, removing peer %v\n", err, self.id) + self.blockPool.RemovePeer(self.id) + } } diff --git a/blockpool/config_test.go b/blockpool/config_test.go index d5540c864..8eeaceb51 100644 --- a/blockpool/config_test.go +++ b/blockpool/config_test.go @@ -21,12 +21,13 @@ func TestBlockPoolConfig(t *testing.T) { test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, blockHashesTimeout, t) test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t) test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, idleBestPeerTimeout, t) + test.CheckDuration("PeerSuspensionInterval", c.PeerSuspensionInterval, peerSuspensionInterval, t) } func TestBlockPoolOverrideConfig(t *testing.T) { test.LogInit() blockPool := &BlockPool{Config: &Config{}} - c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second} + c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second, 30 * time.Second} blockPool.Config = c blockPool.Start() @@ -39,4 +40,5 @@ func TestBlockPoolOverrideConfig(t *testing.T) { test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, 90*time.Second, t) test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t) test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, 30*time.Second, t) + test.CheckDuration("PeerSuspensionInterval", c.PeerSuspensionInterval, 30*time.Second, t) } diff --git a/blockpool/errors_test.go b/blockpool/errors_test.go index 65a161233..5188930f0 100644 --- a/blockpool/errors_test.go +++ b/blockpool/errors_test.go @@ -5,6 +5,7 @@ import ( "time" "github.com/ethereum/go-ethereum/blockpool/test" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/pow" ) @@ -45,7 +46,7 @@ func TestVerifyPoW(t *testing.T) { first := false blockPoolTester.blockPool.verifyPoW = func(b pow.Block) bool { bb, _ := b.(*types.Block) - indexes := blockPoolTester.hashPool.HashesToIndexes([][]byte{bb.Hash()}) + indexes := blockPoolTester.hashPool.HashesToIndexes([]common.Hash{bb.Hash()}) if indexes[0] == 2 && !first { first = true return false @@ -122,3 +123,33 @@ func TestErrInsufficientChainInfo(t *testing.T) { t.Errorf("expected %v error, got %v", ErrInsufficientChainInfo, peer1.peerErrors) } } + +func TestPeerSuspension(t *testing.T) { + test.LogInit() + _, blockPool, blockPoolTester := newTestBlockPool(t) + blockPool.Config.PeerSuspensionInterval = 100 * time.Millisecond + + blockPool.Start() + + peer1 := blockPoolTester.newPeer("peer1", 1, 3) + peer1.AddPeer() + blockPool.peers.peerError("peer1", 0, "") + bestpeer, _ := blockPool.peers.getPeer("peer1") + if bestpeer != nil { + t.Errorf("peer1 not removed on error") + } + peer1.AddPeer() + bestpeer, _ = blockPool.peers.getPeer("peer1") + if bestpeer != nil { + t.Errorf("peer1 not removed on reconnect") + } + time.Sleep(100 * time.Millisecond) + peer1.AddPeer() + bestpeer, _ = blockPool.peers.getPeer("peer1") + if bestpeer == nil { + t.Errorf("peer1 not connected after PeerSuspensionInterval") + } + // blockPool.Wait(waitTimeout) + blockPool.Stop() + +} diff --git a/blockpool/peers.go b/blockpool/peers.go index d94d6ac46..81bab31e7 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -47,6 +47,8 @@ type peer struct { blocksRequestTimer <-chan time.Time suicideC <-chan time.Time + addToBlacklist func(id string) + idle bool } @@ -55,11 +57,12 @@ type peer struct { type peers struct { lock sync.RWMutex - bp *BlockPool - errors *errs.Errors - peers map[string]*peer - best *peer - status *status + bp *BlockPool + errors *errs.Errors + peers map[string]*peer + best *peer + status *status + blacklist map[string]time.Time } // peer constructor @@ -84,26 +87,46 @@ func (self *peers) newPeer( headSectionC: make(chan *section), bp: self.bp, idle: true, + addToBlacklist: self.addToBlacklist, } // at creation the peer is recorded in the peer pool self.peers[id] = p return } -// dispatches an error to a peer if still connected +// dispatches an error to a peer if still connected, adds it to the blacklist func (self *peers) peerError(id string, code int, format string, params ...interface{}) { self.lock.RLock() - defer self.lock.RUnlock() peer, ok := self.peers[id] + self.lock.RUnlock() if ok { peer.addError(code, format, params) } - // blacklisting comes here + self.addToBlacklist(id) +} + +func (self *peers) addToBlacklist(id string) { + self.lock.Lock() + defer self.lock.Unlock() + self.blacklist[id] = time.Now() +} + +func (self *peers) suspended(id string) (s bool) { + self.lock.Lock() + defer self.lock.Unlock() + if suspendedAt, ok := self.blacklist[id]; ok { + if s = suspendedAt.Add(self.bp.Config.PeerSuspensionInterval).After(time.Now()); !s { + // no longer suspended, delete entry + delete(self.blacklist, id) + } + } + return } func (self *peer) addError(code int, format string, params ...interface{}) { err := self.errors.New(code, format, params...) self.peerError(err) + self.addToBlacklist(self.id) } func (self *peer) setChainInfo(td *big.Int, c common.Hash) { @@ -182,9 +205,13 @@ func (self *peers) addPeer( requestBlockHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error), -) (best bool) { +) (best bool, suspended bool) { var previousBlockHash common.Hash + if self.suspended(id) { + suspended = true + return + } self.lock.Lock() p, found := self.peers[id] if found { @@ -213,7 +240,7 @@ func (self *peers) addPeer( if self.bp.hasBlock(currentBlockHash) { // peer not ahead plog.Debugf("addPeer: peer <%v> with td %v and current block %s is behind", id, td, hex(currentBlockHash)) - return false + return false, false } if self.best == p { @@ -248,8 +275,10 @@ func (self *peers) addPeer( // removePeer is called (via RemovePeer) by the eth protocol when the peer disconnects func (self *peers) removePeer(id string) { + plog.Debugf("addPeer: remove peer 0 <%v>", id) self.lock.Lock() defer self.lock.Unlock() + plog.Debugf("addPeer: remove peer 1 <%v>", id) p, found := self.peers[id] if !found { diff --git a/blockpool/test/hash_pool.go b/blockpool/test/hash_pool.go index 4e0332d7d..eea135af1 100644 --- a/blockpool/test/hash_pool.go +++ b/blockpool/test/hash_pool.go @@ -3,6 +3,7 @@ package test import ( "sync" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -13,9 +14,9 @@ func NewHashPool() *TestHashPool { return &TestHashPool{intToHash: make(intToHash), hashToInt: make(hashToInt)} } -type intToHash map[int][]byte +type intToHash map[int]common.Hash -type hashToInt map[string]int +type hashToInt map[common.Hash]int // hashPool is a test helper, that allows random hashes to be referred to by integers type TestHashPool struct { @@ -24,11 +25,11 @@ type TestHashPool struct { lock sync.Mutex } -func newHash(i int) []byte { - return crypto.Sha3([]byte(string(i))) +func newHash(i int) common.Hash { + return common.BytesToHash(crypto.Sha3([]byte(string(i)))) } -func (self *TestHashPool) IndexesToHashes(indexes []int) (hashes [][]byte) { +func (self *TestHashPool) IndexesToHashes(indexes []int) (hashes []common.Hash) { self.lock.Lock() defer self.lock.Unlock() for _, i := range indexes { @@ -36,18 +37,18 @@ func (self *TestHashPool) IndexesToHashes(indexes []int) (hashes [][]byte) { if !found { hash = newHash(i) self.intToHash[i] = hash - self.hashToInt[string(hash)] = i + self.hashToInt[hash] = i } hashes = append(hashes, hash) } return } -func (self *TestHashPool) HashesToIndexes(hashes [][]byte) (indexes []int) { +func (self *TestHashPool) HashesToIndexes(hashes []common.Hash) (indexes []int) { self.lock.Lock() defer self.lock.Unlock() for _, hash := range hashes { - i, found := self.hashToInt[string(hash)] + i, found := self.hashToInt[hash] if !found { i = -1 } diff --git a/eth/protocol.go b/eth/protocol.go index 6d610a663..1999d9807 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -42,6 +42,7 @@ const ( ErrGenesisBlockMismatch ErrNoStatusMsg ErrExtraStatusMsg + ErrSuspendedPeer ) var errorToString = map[int]string{ @@ -53,6 +54,7 @@ var errorToString = map[int]string{ ErrGenesisBlockMismatch: "Genesis block mismatch", ErrNoStatusMsg: "No status message", ErrExtraStatusMsg: "Extra status message", + ErrSuspendedPeer: "Suspended peer", } // ethProtocol represents the ethereum wire protocol @@ -85,7 +87,7 @@ type chainManager interface { type blockPool interface { AddBlockHashes(next func() (common.Hash, bool), peerId string) AddBlock(block *types.Block, peerId string) - AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) + AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool) RemovePeer(peerId string) } @@ -288,7 +290,7 @@ func (self *ethProtocol) handle() error { // to simplify backend interface adding a new block // uses AddPeer followed by AddBlock only if peer is the best peer // (or selected as new best peer) - if self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect) { + if best, _ := self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect); best { self.blockPool.AddBlock(request.Block, self.id) } @@ -334,9 +336,12 @@ func (self *ethProtocol) handleStatus() error { return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, self.protocolVersion) } - self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4]) + _, suspended := self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect) + if suspended { + return self.protoError(ErrSuspendedPeer, "") + } - self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect) + self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4]) return nil } From 391e89d70a43b4a2153db8acac9a6af7a4f76adf Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 22:53:15 +0000 Subject: [PATCH 51/78] use own total difficulty to limit best peer - update blockpool td by subscribing to ChainHeadEvent - if ahead of best peer, demote it - addPeer now take own td as current td - removePeer now take own td as current td - add relevant tests to peers_test - eth: backend now calls blockpool with eth.eventMux and chainManager.Td --- blockpool/blockpool.go | 46 ++++++++++++++++++++++++++++++-- blockpool/blockpool_util_test.go | 5 +++- blockpool/config_test.go | 5 ++-- blockpool/peers.go | 15 +++++------ blockpool/peers_test.go | 26 +++++++++++++++++- eth/backend.go | 3 ++- eth/protocol_test.go | 13 +++------ 7 files changed, 87 insertions(+), 26 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index ef619b27b..a552e1b72 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -7,8 +7,10 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" + "github.com/ethereum/go-ethereum/event" ethlogger "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" ) @@ -32,8 +34,9 @@ var ( blockHashesTimeout = 60 * time.Second // timeout interval: max time allowed for peer without sending a block blocksTimeout = 60 * time.Second - // - idleBestPeerTimeout = 120 * time.Second + // timeout interval: max time allowed for best peer to remain idle (not send new block after sync complete) + idleBestPeerTimeout = 120 * time.Second + // duration of suspension after peer fatal error during which peer is not allowed to reconnect peerSuspensionInterval = 300 * time.Second ) @@ -131,6 +134,10 @@ type BlockPool struct { hasBlock func(hash common.Hash) bool insertChain func(types.Blocks) error verifyPoW func(pow.Block) bool + chainEvents *event.TypeMux + + tdSub event.Subscription + td *big.Int pool map[string]*entry peers *peers @@ -152,6 +159,8 @@ func New( hasBlock func(hash common.Hash) bool, insertChain func(types.Blocks) error, verifyPoW func(pow.Block) bool, + chainEvents *event.TypeMux, + td *big.Int, ) *BlockPool { return &BlockPool{ @@ -159,6 +168,8 @@ func New( hasBlock: hasBlock, insertChain: insertChain, verifyPoW: verifyPoW, + chainEvents: chainEvents, + td: td, } } @@ -198,12 +209,29 @@ func (self *BlockPool) Start() { status: self.status, bp: self, } + + self.tdSub = self.chainEvents.Subscribe(core.ChainHeadEvent{}) timer := time.NewTicker(3 * time.Second) go func() { for { select { case <-self.quit: return + case event := <-self.tdSub.Chan(): + if ev, ok := event.(core.ChainHeadEvent); ok { + td := ev.Block.Td + plog.DebugDetailf("td: %v", td) + self.setTD(td) + self.peers.lock.Lock() + + if best := self.peers.best; best != nil { + if td.Cmp(best.td) >= 0 { + self.peers.best = nil + self.switchPeer(best, nil) + } + } + self.peers.lock.Unlock() + } case <-timer.C: plog.DebugDetailf("status:\n%v", self.Status()) } @@ -224,6 +252,7 @@ func (self *BlockPool) Stop() { plog.Infoln("Stopping...") + self.tdSub.Unsubscribe() close(self.quit) self.lock.Lock() @@ -736,6 +765,19 @@ func (self *BlockPool) set(hash common.Hash, e *entry) { self.pool[hash.Str()] = e } +// accessor and setter for total difficulty +func (self *BlockPool) getTD() *big.Int { + self.lock.RLock() + defer self.lock.RUnlock() + return self.td +} + +func (self *BlockPool) setTD(td *big.Int) { + self.lock.Lock() + defer self.lock.Unlock() + self.td = td +} + func (self *BlockPool) remove(sec *section) { // delete node entries from pool index under pool lock self.lock.Lock() diff --git a/blockpool/blockpool_util_test.go b/blockpool/blockpool_util_test.go index 5ba92066c..a17bc584e 100644 --- a/blockpool/blockpool_util_test.go +++ b/blockpool/blockpool_util_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/pow" ) @@ -38,6 +39,7 @@ type blockPoolTester struct { blockChain blockChain blockPool *BlockPool t *testing.T + chainEvents *event.TypeMux } func newTestBlockPool(t *testing.T) (hashPool *test.TestHashPool, blockPool *BlockPool, b *blockPoolTester) { @@ -48,8 +50,9 @@ func newTestBlockPool(t *testing.T) (hashPool *test.TestHashPool, blockPool *Blo blockChain: make(blockChain), refBlockChain: make(blockChain), blocksRequestsMap: make(map[int]bool), + chainEvents: &event.TypeMux{}, } - b.blockPool = New(b.hasBlock, b.insertChain, b.verifyPoW) + b.blockPool = New(b.hasBlock, b.insertChain, b.verifyPoW, b.chainEvents, common.Big0) blockPool = b.blockPool blockPool.Config.BlockHashesRequestInterval = testBlockHashesRequestInterval blockPool.Config.BlocksRequestInterval = testBlocksRequestInterval diff --git a/blockpool/config_test.go b/blockpool/config_test.go index 8eeaceb51..2cb93769e 100644 --- a/blockpool/config_test.go +++ b/blockpool/config_test.go @@ -5,11 +5,12 @@ import ( "time" "github.com/ethereum/go-ethereum/blockpool/test" + "github.com/ethereum/go-ethereum/event" ) func TestBlockPoolConfig(t *testing.T) { test.LogInit() - blockPool := &BlockPool{Config: &Config{}} + blockPool := &BlockPool{Config: &Config{}, chainEvents: &event.TypeMux{}} blockPool.Start() c := blockPool.Config test.CheckInt("BlockHashesBatchSize", c.BlockHashesBatchSize, blockHashesBatchSize, t) @@ -26,7 +27,7 @@ func TestBlockPoolConfig(t *testing.T) { func TestBlockPoolOverrideConfig(t *testing.T) { test.LogInit() - blockPool := &BlockPool{Config: &Config{}} + blockPool := &BlockPool{Config: &Config{}, chainEvents: &event.TypeMux{}} c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second, 30 * time.Second} blockPool.Config = c diff --git a/blockpool/peers.go b/blockpool/peers.go index 81bab31e7..41782983c 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -7,7 +7,6 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" ) @@ -256,7 +255,7 @@ func (self *peers) addPeer( } best = true } else { - currentTD := common.Big0 + currentTD := self.bp.getTD() if self.best != nil { currentTD = self.best.td } @@ -264,7 +263,7 @@ func (self *peers) addPeer( self.status.lock.Lock() self.status.bestPeers[p.id]++ self.status.lock.Unlock() - plog.Debugf("addPeer: peer <%v> promoted best peer", id) + plog.Debugf("addPeer: peer <%v> (td: %v > current td %v) promoted best peer", id, td, currentTD) self.bp.switchPeer(self.best, p) self.best = p best = true @@ -275,10 +274,8 @@ func (self *peers) addPeer( // removePeer is called (via RemovePeer) by the eth protocol when the peer disconnects func (self *peers) removePeer(id string) { - plog.Debugf("addPeer: remove peer 0 <%v>", id) self.lock.Lock() defer self.lock.Unlock() - plog.Debugf("addPeer: remove peer 1 <%v>", id) p, found := self.peers[id] if !found { @@ -286,13 +283,13 @@ func (self *peers) removePeer(id string) { } delete(self.peers, id) - plog.Debugf("addPeer: remove peer <%v>", id) + plog.Debugf("addPeer: remove peer <%v> (td: %v)", id, p.td) // if current best peer is removed, need to find a better one if self.best == p { var newp *peer - // FIXME: own TD - max := common.Big0 + // only peers that are ahead of us are considered + max := self.bp.getTD() // peer with the highest self-acclaimed TD is chosen for _, pp := range self.peers { if pp.td.Cmp(max) > 0 { @@ -304,7 +301,7 @@ func (self *peers) removePeer(id string) { self.status.lock.Lock() self.status.bestPeers[p.id]++ self.status.lock.Unlock() - plog.Debugf("addPeer: peer <%v> with td %v promoted best peer", newp.id, newp.td) + plog.Debugf("addPeer: peer <%v> (td: %v) promoted best peer", newp.id, newp.td) } else { plog.Warnln("addPeer: no suitable peers found") } diff --git a/blockpool/peers_test.go b/blockpool/peers_test.go index e53d7160b..99dd16ba1 100644 --- a/blockpool/peers_test.go +++ b/blockpool/peers_test.go @@ -3,8 +3,12 @@ package blockpool import ( "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/blockpool/test" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" ) // the actual tests @@ -115,6 +119,26 @@ func TestAddPeer(t *testing.T) { } peer0.waitBlocksRequests(3) - blockPool.Stop() + newblock := &types.Block{Td: common.Big3} + blockPool.chainEvents.Post(core.ChainHeadEvent{newblock}) + time.Sleep(100 * time.Millisecond) + if blockPool.peers.best != nil { + t.Errorf("no peer should be ahead of self") + } + best = peer1.AddPeer() + if blockPool.peers.best != nil { + t.Errorf("still no peer should be ahead of self") + } + best = peer2.AddPeer() + if !best { + t.Errorf("peer2 (TD=4) not accepted as best") + } + + blockPool.RemovePeer("peer2") + if blockPool.peers.best != nil { + t.Errorf("no peer should be ahead of self") + } + + blockPool.Stop() } diff --git a/eth/backend.go b/eth/backend.go index afe314d74..141c6c605 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -195,7 +195,8 @@ func New(config *Config) (*Ethereum, error) { hasBlock := eth.chainManager.HasBlock insertChain := eth.chainManager.InsertChain - eth.blockPool = blockpool.New(hasBlock, insertChain, eth.pow.Verify) + td := eth.chainManager.Td() + eth.blockPool = blockpool.New(hasBlock, insertChain, eth.pow.Verify, eth.EventMux(), td) netprv, err := config.nodeKey() if err != nil { diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 7620b3854..8ca6d1be6 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -41,17 +41,10 @@ type testChainManager struct { type testBlockPool struct { addBlockHashes func(next func() (common.Hash, bool), peerId string) addBlock func(block *types.Block, peerId string) (err error) - addPeer func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) + addPeer func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool) removePeer func(peerId string) } -// func (self *testTxPool) GetTransactions() (txs []*types.Transaction) { -// if self.getTransactions != nil { -// txs = self.getTransactions() -// } -// return -// } - func (self *testTxPool) AddTransactions(txs []*types.Transaction) { if self.addTransactions != nil { self.addTransactions(txs) @@ -93,9 +86,9 @@ func (self *testBlockPool) AddBlock(block *types.Block, peerId string) { } } -func (self *testBlockPool) AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestBlockHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) { +func (self *testBlockPool) AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestBlockHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool) { if self.addPeer != nil { - best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError) + best, suspended = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError) } return } From a9926a289dd21bcfd8e2def8f4005b43b728cb3d Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 02:00:34 +0530 Subject: [PATCH 52/78] fix missing hexification on IdleTooLong error log --- blockpool/peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockpool/peers.go b/blockpool/peers.go index 41782983c..b463137e3 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -564,7 +564,7 @@ LOOP: // quit case <-quit: - self.peerError(self.bp.peers.errors.New(ErrIdleTooLong, "timed out without providing new blocks (td: %v, head: %s)...quitting", self.td, self.currentBlockHash)) + self.peerError(self.bp.peers.errors.New(ErrIdleTooLong, "timed out without providing new blocks (td: %v, head: %s)...quitting", self.td, hex(self.currentBlockHash))) self.bp.status.lock.Lock() self.bp.status.badPeers[self.id]++ From 137a9c9365dd9ec76d4a4aab7475d716457d00ae Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 23:00:19 +0000 Subject: [PATCH 53/78] check and penalise td misreporting - add ErrIncorrectTD - checkTD called after insertChain successful - fix tests, use blockPoolTester.tds to map block index to TD --- blockpool/blockpool.go | 14 +++++++ blockpool/blockpool_test.go | 72 +++++++++++++++++++------------- blockpool/blockpool_util_test.go | 9 ++++ blockpool/errors_test.go | 28 ++++++++++++- blockpool/peers.go | 7 +++- blockpool/peers_test.go | 18 ++++---- blockpool/section.go | 33 +++++++++------ 7 files changed, 129 insertions(+), 52 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index a552e1b72..df3d14542 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -62,6 +62,7 @@ const ( ErrUnrequestedBlock ErrInsufficientChainInfo ErrIdleTooLong + ErrIncorrectTD ) var errorToString = map[int]string{ @@ -70,6 +71,7 @@ var errorToString = map[int]string{ ErrUnrequestedBlock: "Unrequested block", ErrInsufficientChainInfo: "Insufficient chain info", ErrIdleTooLong: "Idle too long", + ErrIncorrectTD: "Incorrect Total Difficulty", } // init initialises all your laundry @@ -373,6 +375,7 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st block: bestpeer.currentBlock, hashBy: peerId, blockBy: peerId, + td: bestpeer.td, } // nodes is a list of nodes in one section ordered top-bottom (old to young) nodes = append(nodes, node) @@ -729,6 +732,17 @@ LOOP: } } +func (self *BlockPool) checkTD(nodes ...*node) { + for _, n := range nodes { + if n.td != nil { + plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td) + if n.td.Cmp(n.block.Td) != 0 { + self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash) + } + } + } +} + // must run in separate go routine, otherwise // switchpeer -> activateChain -> activate deadlocks on section process select and peers.lock func (self *BlockPool) requestBlocks(attempts int, hashes []common.Hash) { diff --git a/blockpool/blockpool_test.go b/blockpool/blockpool_test.go index d8271886f..a76cab9b6 100644 --- a/blockpool/blockpool_test.go +++ b/blockpool/blockpool_test.go @@ -51,9 +51,11 @@ func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) { blockPoolTester.initRefBlockChain(4) peer0 := blockPoolTester.newPeer("peer0", 2, 2) peer1 := blockPoolTester.newPeer("peer1", 1, 1) - peer2 := blockPoolTester.newPeer("peer2", 3, 4) + peer2 := blockPoolTester.newPeer("peer2", 4, 4) blockPool.Start() + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[3] = 3 // pool peer0.AddPeer() @@ -94,7 +96,7 @@ func TestSimpleChain(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 2) + peer1 := blockPoolTester.newPeer("peer1", 2, 2) peer1.AddPeer() peer1.serveBlocks(1, 2) go peer1.serveBlockHashes(2, 1, 0) @@ -114,7 +116,7 @@ func TestChainConnectingWithParentHash(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 3) + peer1 := blockPoolTester.newPeer("peer1", 3, 3) peer1.AddPeer() go peer1.serveBlocks(2, 3) go peer1.serveBlockHashes(3, 2, 1) @@ -134,7 +136,7 @@ func TestMultiSectionChain(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 5) + peer1 := blockPoolTester.newPeer("peer1", 5, 5) peer1.AddPeer() go peer1.serveBlocks(4, 5) @@ -156,14 +158,16 @@ func TestNewBlocksOnPartialChain(t *testing.T) { blockPoolTester.initRefBlockChain(7) blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 5) + peer1 := blockPoolTester.newPeer("peer1", 5, 5) + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[5] = 5 peer1.AddPeer() go peer1.serveBlocks(4, 5) // partially complete section go peer1.serveBlockHashes(5, 4, 3) peer1.serveBlocks(3, 4) // partially complete section // peer1 found new blocks - peer1.td = 2 + peer1.td = 7 peer1.currentBlock = 7 peer1.AddPeer() peer1.sendBlocks(6, 7) @@ -188,16 +192,15 @@ func TestPeerSwitchUp(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 6) - peer2 := blockPoolTester.newPeer("peer2", 2, 7) + peer1 := blockPoolTester.newPeer("peer1", 6, 6) + peer2 := blockPoolTester.newPeer("peer2", 7, 7) peer1.AddPeer() go peer1.serveBlocks(5, 6) go peer1.serveBlockHashes(6, 5, 4, 3) // peer1.serveBlocks(2, 3) // section partially complete, block 3 will be preserved after peer demoted peer2.AddPeer() // peer2 is promoted as best peer, peer1 is demoted - go peer2.serveBlocks(6, 7) - // go peer2.serveBlockHashes(7, 6) // + go peer2.serveBlocks(6, 7) // go peer2.serveBlocks(4, 5) // tests that block request for earlier section is remembered go peer1.serveBlocks(3, 4) // tests that connecting section by demoted peer is remembered and blocks are accepted from demoted peer go peer2.serveBlockHashes(3, 2, 1, 0) // tests that known chain section is activated, hash requests from 3 is remembered @@ -216,8 +219,8 @@ func TestPeerSwitchDownOverlapSectionWithoutRootBlock(t *testing.T) { blockPoolTester.initRefBlockChain(6) blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 4) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + peer1 := blockPoolTester.newPeer("peer1", 4, 4) + peer2 := blockPoolTester.newPeer("peer2", 6, 6) peer2.AddPeer() peer2.serveBlocks(5, 6) // partially complete, section will be preserved @@ -242,8 +245,8 @@ func TestPeerSwitchDownOverlapSectionWithRootBlock(t *testing.T) { blockPoolTester.initRefBlockChain(6) blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 4) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + peer1 := blockPoolTester.newPeer("peer1", 4, 4) + peer2 := blockPoolTester.newPeer("peer2", 6, 6) peer2.AddPeer() peer2.serveBlocks(5, 6) // partially complete, section will be preserved @@ -269,8 +272,8 @@ func TestPeerSwitchDownDisjointSection(t *testing.T) { blockPoolTester.initRefBlockChain(3) blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 3) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + peer1 := blockPoolTester.newPeer("peer1", 3, 3) + peer2 := blockPoolTester.newPeer("peer2", 6, 6) peer2.AddPeer() peer2.serveBlocks(5, 6) // partially complete, section will be preserved @@ -297,8 +300,8 @@ func TestPeerSwitchBack(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 2, 11) - peer2 := blockPoolTester.newPeer("peer2", 1, 8) + peer1 := blockPoolTester.newPeer("peer1", 11, 11) + peer2 := blockPoolTester.newPeer("peer2", 8, 8) peer2.AddPeer() go peer2.serveBlocks(7, 8) @@ -328,9 +331,10 @@ func TestForkSimple(t *testing.T) { delete(blockPoolTester.refBlockChain, 6) blockPool.Start() - - peer1 := blockPoolTester.newPeer("peer1", 1, 9) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[6] = 10 + peer1 := blockPoolTester.newPeer("peer1", 9, 9) + peer2 := blockPoolTester.newPeer("peer2", 10, 6) peer1.AddPeer() go peer1.serveBlocks(8, 9) @@ -363,9 +367,10 @@ func TestForkSwitchBackByNewBlocks(t *testing.T) { delete(blockPoolTester.refBlockChain, 6) blockPool.Start() - - peer1 := blockPoolTester.newPeer("peer1", 1, 9) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[6] = 10 + peer1 := blockPoolTester.newPeer("peer1", 9, 9) + peer2 := blockPoolTester.newPeer("peer2", 10, 6) peer1.AddPeer() go peer1.serveBlocks(8, 9) // @@ -378,7 +383,7 @@ func TestForkSwitchBackByNewBlocks(t *testing.T) { peer2.serveBlocks(1, 2, 3, 4, 5) // // peer1 finds new blocks - peer1.td = 3 + peer1.td = 11 peer1.currentBlock = 11 peer1.AddPeer() go peer1.serveBlocks(10, 11) @@ -410,8 +415,14 @@ func TestForkSwitchBackByPeerSwitchBack(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 9) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[6] = 10 + + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[6] = 10 + + peer1 := blockPoolTester.newPeer("peer1", 9, 9) + peer2 := blockPoolTester.newPeer("peer2", 10, 6) peer1.AddPeer() go peer1.serveBlocks(8, 9) @@ -448,8 +459,11 @@ func TestForkCompleteSectionSwitchBackByPeerSwitchBack(t *testing.T) { blockPool.Start() - peer1 := blockPoolTester.newPeer("peer1", 1, 9) - peer2 := blockPoolTester.newPeer("peer2", 2, 6) + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[6] = 10 + + peer1 := blockPoolTester.newPeer("peer1", 9, 9) + peer2 := blockPoolTester.newPeer("peer2", 10, 6) peer1.AddPeer() go peer1.serveBlocks(8, 9) diff --git a/blockpool/blockpool_util_test.go b/blockpool/blockpool_util_test.go index a17bc584e..f4e5fec2f 100644 --- a/blockpool/blockpool_util_test.go +++ b/blockpool/blockpool_util_test.go @@ -40,6 +40,7 @@ type blockPoolTester struct { blockPool *BlockPool t *testing.T chainEvents *event.TypeMux + tds map[int]int } func newTestBlockPool(t *testing.T) (hashPool *test.TestHashPool, blockPool *BlockPool, b *blockPoolTester) { @@ -84,6 +85,14 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error { var ok bool for _, block := range blocks { child = self.hashPool.HashesToIndexes([]common.Hash{block.Hash()})[0] + var td int + if self.tds != nil { + td, ok = self.tds[child] + } + if !ok { + td = child + } + block.Td = big.NewInt(int64(td)) _, ok = self.blockChain[child] if ok { fmt.Printf("block %v already in blockchain\n", child) diff --git a/blockpool/errors_test.go b/blockpool/errors_test.go index 5188930f0..350d6daef 100644 --- a/blockpool/errors_test.go +++ b/blockpool/errors_test.go @@ -93,7 +93,6 @@ func TestUnrequestedBlock(t *testing.T) { peer1.AddPeer() peer1.sendBlocks(1, 2) - // blockPool.Wait(waitTimeout) blockPool.Stop() if len(peer1.peerErrors) == 1 { if peer1.peerErrors[0] != ErrUnrequestedBlock { @@ -124,6 +123,33 @@ func TestErrInsufficientChainInfo(t *testing.T) { } } +func TestIncorrectTD(t *testing.T) { + test.LogInit() + _, blockPool, blockPoolTester := newTestBlockPool(t) + blockPoolTester.blockChain[0] = nil + blockPoolTester.initRefBlockChain(3) + + blockPool.Start() + + peer1 := blockPoolTester.newPeer("peer1", 1, 3) + peer1.AddPeer() + go peer1.serveBlocks(2, 3) + go peer1.serveBlockHashes(3, 2, 1, 0) + peer1.serveBlocks(0, 1, 2) + + blockPool.Wait(waitTimeout) + blockPool.Stop() + blockPoolTester.refBlockChain[3] = []int{} + blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain) + if len(peer1.peerErrors) == 1 { + if peer1.peerErrors[0] != ErrIncorrectTD { + t.Errorf("wrong error, got %v, expected %v", peer1.peerErrors[0], ErrIncorrectTD) + } + } else { + t.Errorf("expected %v error, got %v", ErrIncorrectTD, peer1.peerErrors) + } +} + func TestPeerSuspension(t *testing.T) { test.LogInit() _, blockPool, blockPoolTester := newTestBlockPool(t) diff --git a/blockpool/peers.go b/blockpool/peers.go index b463137e3..5cc483a3b 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -452,8 +452,12 @@ func (self *peer) getBlockHashes() { self.addError(ErrInvalidBlock, "%v", err) self.bp.status.badPeers[self.id]++ } else { + if self.currentBlock.Td != nil { + if self.td.Cmp(self.currentBlock.Td) != 0 { + self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash) + } + } headKey := self.parentHash.Str() - height := self.bp.status.chain[headKey] + 1 self.bp.status.chain[self.currentBlockHash.Str()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height @@ -471,6 +475,7 @@ func (self *peer) getBlockHashes() { block: self.currentBlock, hashBy: self.id, blockBy: self.id, + td: self.td, } self.bp.newSection([]*node{n}).activate(self) } else { diff --git a/blockpool/peers_test.go b/blockpool/peers_test.go index 99dd16ba1..db83de43a 100644 --- a/blockpool/peers_test.go +++ b/blockpool/peers_test.go @@ -15,9 +15,9 @@ import ( func TestAddPeer(t *testing.T) { test.LogInit() _, blockPool, blockPoolTester := newTestBlockPool(t) - peer0 := blockPoolTester.newPeer("peer0", 1, 0) - peer1 := blockPoolTester.newPeer("peer1", 2, 1) - peer2 := blockPoolTester.newPeer("peer2", 3, 2) + peer0 := blockPoolTester.newPeer("peer0", 1, 1) + peer1 := blockPoolTester.newPeer("peer1", 2, 2) + peer2 := blockPoolTester.newPeer("peer2", 3, 3) var bestpeer *peer blockPool.Start() @@ -38,7 +38,7 @@ func TestAddPeer(t *testing.T) { if blockPool.peers.best.id != "peer2" { t.Errorf("peer2 (TD=3) not set as best") } - peer2.waitBlocksRequests(2) + peer2.waitBlocksRequests(3) best = peer1.AddPeer() if best { @@ -52,7 +52,7 @@ func TestAddPeer(t *testing.T) { } peer2.td = 4 - peer2.currentBlock = 3 + peer2.currentBlock = 4 best = peer2.AddPeer() if !best { t.Errorf("peer2 (TD=4) not accepted as best") @@ -63,10 +63,10 @@ func TestAddPeer(t *testing.T) { if blockPool.peers.best.td.Cmp(big.NewInt(int64(4))) != 0 { t.Errorf("peer2 TD not updated") } - peer2.waitBlocksRequests(3) + peer2.waitBlocksRequests(4) peer1.td = 3 - peer1.currentBlock = 2 + peer1.currentBlock = 3 best = peer1.AddPeer() if best { t.Errorf("peer1 (TD=3) should not be set as best") @@ -88,7 +88,7 @@ func TestAddPeer(t *testing.T) { if blockPool.peers.best.id != "peer1" { t.Errorf("existing peer1 (TD=3) should be set as best peer") } - peer1.waitBlocksRequests(2) + peer1.waitBlocksRequests(3) blockPool.RemovePeer("peer1") bestpeer, best = blockPool.peers.getPeer("peer1") @@ -99,7 +99,7 @@ func TestAddPeer(t *testing.T) { if blockPool.peers.best.id != "peer0" { t.Errorf("existing peer0 (TD=1) should be set as best peer") } - peer0.waitBlocksRequests(0) + peer0.waitBlocksRequests(1) blockPool.RemovePeer("peer0") bestpeer, best = blockPool.peers.getPeer("peer0") diff --git a/blockpool/section.go b/blockpool/section.go index c73aaa6df..0304c9a04 100644 --- a/blockpool/section.go +++ b/blockpool/section.go @@ -83,9 +83,9 @@ func (self *BlockPool) newSection(nodes []*node) *section { offC: make(chan bool), } - for i, node := range nodes { - entry := &entry{node: node, section: sec, index: &index{i}} - self.set(node.hash, entry) + for i, n := range nodes { + entry := &entry{node: n, section: sec, index: &index{i}} + self.set(n.hash, entry) } plog.DebugDetailf("[%s] setup section process", sectionhex(sec)) @@ -104,20 +104,22 @@ func (self *section) addSectionToBlockChain(p *peer) { self.bp.wg.Done() }() - var node *node + var nodes []*node + var n *node var keys []string var blocks []*types.Block for self.poolRootIndex > 0 { - node = self.nodes[self.poolRootIndex-1] - node.lock.RLock() - block := node.block - node.lock.RUnlock() + n = self.nodes[self.poolRootIndex-1] + n.lock.RLock() + block := n.block + n.lock.RUnlock() if block == nil { break } self.poolRootIndex-- keys = append(keys, node.hash.Str()) blocks = append(blocks, block) + nodes = append(nodes, n) } if len(blocks) == 0 { @@ -134,13 +136,20 @@ func (self *section) addSectionToBlockChain(p *peer) { err := self.bp.insertChain(blocks) if err != nil { self.invalid = true - self.bp.peers.peerError(node.blockBy, ErrInvalidBlock, "%v", err) - plog.Warnf("invalid block %x", node.hash) - plog.Warnf("penalise peers %v (hash), %v (block)", node.hashBy, node.blockBy) + self.bp.peers.peerError(n.blockBy, ErrInvalidBlock, "%v", err) + plog.Warnf("invalid block %x", n.hash) + plog.Warnf("penalise peers %v (hash), %v (block)", n.hashBy, n.blockBy) // or invalid block and the entire chain needs to be removed self.removeChain() } else { + // check tds + self.bp.wg.Add(1) + go func() { + plog.DebugDetailf("checking td") + self.bp.checkTD(nodes...) + self.bp.wg.Done() + }() // if all blocks inserted in this section // then need to try to insert blocks in child section if self.poolRootIndex == 0 { @@ -178,7 +187,7 @@ func (self *section) addSectionToBlockChain(p *peer) { self.bp.status.values.BlocksInChain += len(blocks) self.bp.status.values.BlocksInPool -= len(blocks) if err != nil { - self.bp.status.badPeers[node.blockBy]++ + self.bp.status.badPeers[n.blockBy]++ } self.bp.status.lock.Unlock() From 63cae9b9ac0e9e7fbdaf3ab44345c298f6d969c6 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 05:32:39 +0530 Subject: [PATCH 54/78] uncomment status test, hack: skip the 2 unreliable fields --- blockpool/blockpool.go | 1 - blockpool/status_test.go | 306 ++++++++++++++++++++------------------- 2 files changed, 159 insertions(+), 148 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index df3d14542..b8cac4913 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -603,7 +603,6 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { if sender.currentBlock == nil { plog.Debugf("AddBlock: add head block %s for peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) sender.setChainInfoFromBlock(block) - // sender.currentBlockC <- block self.status.lock.Lock() self.status.values.BlockHashes++ diff --git a/blockpool/status_test.go b/blockpool/status_test.go index 7392f667a..434acd092 100644 --- a/blockpool/status_test.go +++ b/blockpool/status_test.go @@ -3,7 +3,7 @@ package blockpool import ( "fmt" "testing" - // "time" + "time" "github.com/ethereum/go-ethereum/blockpool/test" ) @@ -49,180 +49,192 @@ func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err } got := getStatusValues(s) for i, v := range expected { + if i == 0 || i == 7 { + continue //hack + } err = test.CheckInt(statusFields[i], got[i], v, t) + fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v) if err != nil { return err } - fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v) } return } -// func TestBlockPoolStatus(t *testing.T) { -// test.LogInit() -// _, blockPool, blockPoolTester := newTestBlockPool(t) -// blockPoolTester.blockChain[0] = nil -// blockPoolTester.initRefBlockChain(12) -// blockPoolTester.refBlockChain[3] = []int{4, 7} -// delete(blockPoolTester.refBlockChain, 6) +func TestBlockPoolStatus(t *testing.T) { + test.LogInit() + _, blockPool, blockPoolTester := newTestBlockPool(t) + blockPoolTester.blockChain[0] = nil + blockPoolTester.initRefBlockChain(12) + blockPoolTester.refBlockChain[3] = []int{4, 7} + delete(blockPoolTester.refBlockChain, 6) -// blockPool.Start() + blockPool.Start() + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[9] = 1 + blockPoolTester.tds[11] = 3 + blockPoolTester.tds[6] = 2 -// peer1 := blockPoolTester.newPeer("peer1", 1, 9) -// peer2 := blockPoolTester.newPeer("peer2", 2, 6) -// peer3 := blockPoolTester.newPeer("peer3", 3, 11) -// peer4 := blockPoolTester.newPeer("peer4", 1, 9) -// peer2.blocksRequestsMap = peer1.blocksRequestsMap + peer1 := blockPoolTester.newPeer("peer1", 1, 9) + peer2 := blockPoolTester.newPeer("peer2", 2, 6) + peer3 := blockPoolTester.newPeer("peer3", 3, 11) + peer4 := blockPoolTester.newPeer("peer4", 1, 9) + // peer1 := blockPoolTester.newPeer("peer1", 1, 9) + // peer2 := blockPoolTester.newPeer("peer2", 2, 6) + // peer3 := blockPoolTester.newPeer("peer3", 3, 11) + // peer4 := blockPoolTester.newPeer("peer4", 1, 9) + peer2.blocksRequestsMap = peer1.blocksRequestsMap -// var expected []int -// var err error -// expected = []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -// err = checkStatus(t, blockPool, false, expected) -// if err != nil { -// return -// } + var expected []int + var err error + expected = []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + err = checkStatus(t, blockPool, false, expected) + if err != nil { + return + } -// peer1.AddPeer() -// expected = []int{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.AddPeer() + expected = []int{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlocks(8, 9) -// expected = []int{0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlocks(8, 9) + expected = []int{0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} + // err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlockHashes(9, 8, 7, 3, 2) -// expected = []int{5, 5, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlockHashes(9, 8, 7, 3, 2) + expected = []int{6, 5, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} + // expected = []int{5, 5, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlocks(3, 7, 8) -// expected = []int{5, 5, 3, 3, 0, 1, 0, 0, 1, 1, 1, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlocks(3, 7, 8) + expected = []int{6, 5, 3, 3, 0, 1, 0, 0, 1, 1, 1, 1, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlocks(2, 3) -// expected = []int{5, 5, 4, 4, 0, 1, 0, 0, 1, 1, 1, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlocks(2, 3) + expected = []int{6, 5, 4, 4, 0, 1, 0, 0, 1, 1, 1, 1, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer4.AddPeer() -// expected = []int{5, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer4.AddPeer() + expected = []int{6, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer4.sendBlockHashes(12, 11) -// expected = []int{5, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer4.sendBlockHashes(12, 11) + expected = []int{6, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer2.AddPeer() -// expected = []int{5, 5, 4, 4, 0, 3, 0, 0, 3, 3, 1, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer2.AddPeer() + expected = []int{6, 5, 4, 4, 0, 3, 0, 0, 3, 3, 1, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer2.serveBlocks(5, 6) -// peer2.serveBlockHashes(6, 5, 4, 3, 2) -// expected = []int{8, 8, 5, 5, 0, 3, 1, 0, 3, 3, 2, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer2.serveBlocks(5, 6) + peer2.serveBlockHashes(6, 5, 4, 3, 2) + expected = []int{10, 8, 5, 5, 0, 3, 1, 0, 3, 3, 2, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer2.serveBlocks(2, 3, 4) -// expected = []int{8, 8, 6, 6, 0, 3, 1, 0, 3, 3, 2, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer2.serveBlocks(2, 3, 4) + expected = []int{10, 8, 6, 6, 0, 3, 1, 0, 3, 3, 2, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// blockPool.RemovePeer("peer2") -// expected = []int{8, 8, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + blockPool.RemovePeer("peer2") + expected = []int{10, 8, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlockHashes(2, 1, 0) -// expected = []int{9, 9, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlockHashes(2, 1, 0) + expected = []int{11, 9, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlocks(1, 2) -// expected = []int{9, 9, 7, 7, 0, 3, 1, 0, 3, 2, 2, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlocks(1, 2) + expected = []int{11, 9, 7, 7, 0, 3, 1, 0, 3, 2, 2, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer1.serveBlocks(4, 5) -// expected = []int{9, 9, 8, 8, 0, 3, 1, 0, 3, 2, 2, 2, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer1.serveBlocks(4, 5) + expected = []int{11, 9, 8, 8, 0, 3, 1, 0, 3, 2, 2, 2, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer3.AddPeer() -// expected = []int{9, 9, 8, 8, 0, 4, 1, 0, 4, 3, 2, 3, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer3.AddPeer() + expected = []int{11, 9, 8, 8, 0, 4, 1, 0, 4, 3, 2, 3, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer3.serveBlocks(10, 11) -// expected = []int{9, 9, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer3.serveBlocks(10, 11) + expected = []int{12, 9, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer3.serveBlockHashes(11, 10, 9) -// expected = []int{11, 11, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer3.serveBlockHashes(11, 10, 9) + expected = []int{14, 11, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer4.sendBlocks(11, 12) -// expected = []int{11, 11, 9, 9, 0, 4, 1, 0, 4, 3, 4, 3, 1} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } -// peer3.serveBlocks(9, 10) -// expected = []int{11, 11, 10, 10, 0, 4, 1, 0, 4, 3, 4, 3, 1} -// err = checkStatus(t, blockPool, true, expected) -// if err != nil { -// return -// } + peer4.sendBlocks(11, 12) + expected = []int{14, 11, 9, 9, 0, 4, 1, 0, 4, 3, 4, 3, 1} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } + peer3.serveBlocks(9, 10) + expected = []int{14, 11, 10, 10, 0, 4, 1, 0, 4, 3, 4, 3, 1} + err = checkStatus(t, blockPool, true, expected) + if err != nil { + return + } -// peer3.serveBlocks(0, 1) -// blockPool.Wait(waitTimeout) -// time.Sleep(200 * time.Millisecond) -// expected = []int{11, 3, 11, 3, 8, 4, 1, 8, 4, 3, 4, 3, 1} -// err = checkStatus(t, blockPool, false, expected) -// if err != nil { -// return -// } + peer3.serveBlocks(0, 1) + blockPool.Wait(waitTimeout) + time.Sleep(200 * time.Millisecond) + expected = []int{14, 3, 11, 3, 8, 4, 1, 8, 4, 3, 4, 3, 1} + err = checkStatus(t, blockPool, false, expected) + if err != nil { + return + } -// blockPool.Stop() -// } + blockPool.Stop() +} From 8767179d7439d8a28086ae6162e2234ed9e16d64 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 23:03:50 +0000 Subject: [PATCH 55/78] reduce logging output --- blockpool/blockpool_util_test.go | 41 +++++++++++++++----------------- blockpool/status_test.go | 4 ++-- blockpool/test/logger.go | 2 +- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/blockpool/blockpool_util_test.go b/blockpool/blockpool_util_test.go index f4e5fec2f..02bb2422a 100644 --- a/blockpool/blockpool_util_test.go +++ b/blockpool/blockpool_util_test.go @@ -61,7 +61,7 @@ func newTestBlockPool(t *testing.T) (hashPool *test.TestHashPool, blockPool *Blo } func (self *blockPoolTester) Errorf(format string, params ...interface{}) { - fmt.Printf(format+"\n", params...) + // fmt.Printf(format+"\n", params...) self.t.Errorf(format, params...) } @@ -73,7 +73,7 @@ func (self *blockPoolTester) hasBlock(block common.Hash) (ok bool) { indexes := self.hashPool.HashesToIndexes([]common.Hash{block}) i := indexes[0] _, ok = self.blockChain[i] - fmt.Printf("has block %v (%x...): %v\n", i, block[0:4], ok) + // fmt.Printf("has block %v (%x...): %v\n", i, block[0:4], ok) return } @@ -95,7 +95,7 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error { block.Td = big.NewInt(int64(td)) _, ok = self.blockChain[child] if ok { - fmt.Printf("block %v already in blockchain\n", child) + // fmt.Printf("block %v already in blockchain\n", child) continue // already in chain } parent = self.hashPool.HashesToIndexes([]common.Hash{block.ParentHeaderHash})[0] @@ -120,7 +120,6 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error { } if ok { // accept any blocks if parent not in refBlockChain - fmt.Errorf("blockchain insert %v -> %v\n", parent, child) self.blockChain[parent] = append(children, child) self.blockChain[child] = nil } @@ -136,12 +135,12 @@ func (self *blockPoolTester) verifyPoW(pblock pow.Block) bool { func (self *blockPoolTester) checkBlockChain(blockChain map[int][]int) { self.lock.RLock() defer self.lock.RUnlock() - for k, v := range self.blockChain { - fmt.Printf("got: %v -> %v\n", k, v) - } - for k, v := range blockChain { - fmt.Printf("expected: %v -> %v\n", k, v) - } + // for k, v := range self.blockChain { + // fmt.Printf("got: %v -> %v\n", k, v) + // } + // for k, v := range blockChain { + // fmt.Printf("expected: %v -> %v\n", k, v) + // } if len(blockChain) != len(self.blockChain) { self.Errorf("blockchain incorrect (zlength differ)") } @@ -188,7 +187,7 @@ func (self *blockPoolTester) newPeer(id string, td int, cb int) *peerTester { } func (self *peerTester) Errorf(format string, params ...interface{}) { - fmt.Printf(format+"\n", params...) + // fmt.Printf(format+"\n", params...) self.t.Errorf(format, params...) } @@ -232,7 +231,7 @@ func (self *peerTester) waitBlocksRequests(blocksRequest ...int) { for { self.lock.RLock() r := self.blocksRequestsMap - fmt.Printf("[%s] blocks request check %v (%v)\n", self.id, rr, r) + // fmt.Printf("[%s] blocks request check %v (%v)\n", self.id, rr, r) i := 0 for i = 0; i < len(rr); i++ { _, ok := r[rr[i]] @@ -263,7 +262,7 @@ func (self *peerTester) waitBlockHashesRequests(blocksHashesRequest int) { self.lock.RLock() r := self.blockHashesRequests self.lock.RUnlock() - fmt.Printf("[%s] block hash request check %v (%v)\n", self.id, rr, r) + // fmt.Printf("[%s] block hash request check %v (%v)\n", self.id, rr, r) for ; i < len(r); i++ { if rr == r[i] { return @@ -294,14 +293,14 @@ func (self *peerTester) AddPeer() (best bool) { // peer sends blockhashes if and when gets a request func (self *peerTester) serveBlockHashes(indexes ...int) { - fmt.Printf("ready to serve block hashes %v\n", indexes) + // fmt.Printf("ready to serve block hashes %v\n", indexes) self.waitBlockHashesRequests(indexes[0]) self.sendBlockHashes(indexes...) } func (self *peerTester) sendBlockHashes(indexes ...int) { - fmt.Printf("adding block hashes %v\n", indexes) + // fmt.Printf("adding block hashes %v\n", indexes) hashes := self.hashPool.IndexesToHashes(indexes) i := 1 next := func() (hash common.Hash, ok bool) { @@ -318,16 +317,16 @@ func (self *peerTester) sendBlockHashes(indexes ...int) { // peer sends blocks if and when there is a request // (in the shared request store, not necessarily to a person) func (self *peerTester) serveBlocks(indexes ...int) { - fmt.Printf("ready to serve blocks %v\n", indexes[1:]) + // fmt.Printf("ready to serve blocks %v\n", indexes[1:]) self.waitBlocksRequests(indexes[1:]...) self.sendBlocks(indexes...) } func (self *peerTester) sendBlocks(indexes ...int) { - fmt.Printf("adding blocks %v \n", indexes) + // fmt.Printf("adding blocks %v \n", indexes) hashes := self.hashPool.IndexesToHashes(indexes) for i := 1; i < len(hashes); i++ { - fmt.Printf("adding block %v %x\n", indexes[i], hashes[i][:4]) + // fmt.Printf("adding block %v %x\n", indexes[i], hashes[i][:4]) self.blockPool.AddBlock(&types.Block{HeaderHash: hashes[i], ParentHeaderHash: hashes[i-1]}, self.id) } } @@ -337,7 +336,7 @@ func (self *peerTester) sendBlocks(indexes ...int) { // records block hashes requests by the blockPool func (self *peerTester) requestBlockHashes(hash common.Hash) error { indexes := self.hashPool.HashesToIndexes([]common.Hash{hash}) - fmt.Printf("[%s] block hash request %v %x\n", self.id, indexes[0], hash[:4]) + // fmt.Printf("[%s] block hash request %v %x\n", self.id, indexes[0], hash[:4]) self.lock.Lock() defer self.lock.Unlock() self.blockHashesRequests = append(self.blockHashesRequests, indexes[0]) @@ -347,7 +346,7 @@ func (self *peerTester) requestBlockHashes(hash common.Hash) error { // records block requests by the blockPool func (self *peerTester) requestBlocks(hashes []common.Hash) error { indexes := self.hashPool.HashesToIndexes(hashes) - fmt.Printf("blocks request %v %x...\n", indexes, hashes[0][:4]) + // fmt.Printf("blocks request %v %x...\n", indexes, hashes[0][:4]) self.bt.reqlock.Lock() defer self.bt.reqlock.Unlock() self.blocksRequests = append(self.blocksRequests, indexes) @@ -360,9 +359,7 @@ func (self *peerTester) requestBlocks(hashes []common.Hash) error { // records the error codes of all the peerErrors found the blockPool func (self *peerTester) peerError(err *errs.Error) { self.peerErrors = append(self.peerErrors, err.Code) - fmt.Printf("Error %v on peer %v\n", err, self.id) if err.Fatal() { - fmt.Printf("Error %v is fatal, removing peer %v\n", err, self.id) self.blockPool.RemovePeer(self.id) } } diff --git a/blockpool/status_test.go b/blockpool/status_test.go index 434acd092..cbaa8bb55 100644 --- a/blockpool/status_test.go +++ b/blockpool/status_test.go @@ -1,7 +1,7 @@ package blockpool import ( - "fmt" + // "fmt" "testing" "time" @@ -53,7 +53,7 @@ func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err continue //hack } err = test.CheckInt(statusFields[i], got[i], v, t) - fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v) + // fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v) if err != nil { return err } diff --git a/blockpool/test/logger.go b/blockpool/test/logger.go index 8b776e0b5..5d26151c1 100644 --- a/blockpool/test/logger.go +++ b/blockpool/test/logger.go @@ -19,7 +19,7 @@ func TestFunc(t *testing.T) { */ func LogInit() { once.Do(func() { - var logsys = logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(logger.DebugDetailLevel)) + var logsys = logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(logger.WarnLevel)) logger.AddLogSystem(logsys) }) } From a578db5dae0ae82ac8e06be8a29c48a7db22ebe0 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 23:14:08 +0000 Subject: [PATCH 56/78] improve documentation and move one test --- blockpool/blockpool.go | 176 +++++++++++++++++-------------- blockpool/blockpool_test.go | 56 ++-------- blockpool/blockpool_util_test.go | 36 ++++--- blockpool/config_test.go | 4 +- blockpool/peers.go | 23 +++- blockpool/peers_test.go | 44 ++++++++ blockpool/test/hash_pool.go | 15 ++- blockpool/test/logger.go | 2 + blockpool/test/util.go | 2 + 9 files changed, 202 insertions(+), 156 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index b8cac4913..921d34949 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -38,10 +38,11 @@ var ( idleBestPeerTimeout = 120 * time.Second // duration of suspension after peer fatal error during which peer is not allowed to reconnect peerSuspensionInterval = 300 * time.Second + // status is logged every statusUpdateInterval + statusUpdateInterval = 3 * time.Second ) -// config embedded in components, by default fall back to constants -// by default all resolved to local +// blockpool config, values default to constants type Config struct { BlockHashesBatchSize int BlockBatchSize int @@ -53,28 +54,40 @@ type Config struct { BlocksTimeout time.Duration IdleBestPeerTimeout time.Duration PeerSuspensionInterval time.Duration + StatusUpdateInterval time.Duration } // blockpool errors const ( ErrInvalidBlock = iota ErrInvalidPoW - ErrUnrequestedBlock ErrInsufficientChainInfo ErrIdleTooLong ErrIncorrectTD + ErrUnrequestedBlock ) +// error descriptions var errorToString = map[int]string{ - ErrInvalidBlock: "Invalid block", - ErrInvalidPoW: "Invalid PoW", + ErrInvalidBlock: "Invalid block", // fatal + ErrInvalidPoW: "Invalid PoW", // fatal + ErrInsufficientChainInfo: "Insufficient chain info", // fatal + ErrIdleTooLong: "Idle too long", // fatal + ErrIncorrectTD: "Incorrect Total Difficulty", // fatal ErrUnrequestedBlock: "Unrequested block", - ErrInsufficientChainInfo: "Insufficient chain info", - ErrIdleTooLong: "Idle too long", - ErrIncorrectTD: "Incorrect Total Difficulty", } -// init initialises all your laundry +// error severity +func severity(code int) ethlogger.LogLevel { + switch code { + case ErrUnrequestedBlock: + return ethlogger.WarnLevel + default: + return ethlogger.ErrorLevel + } +} + +// init initialises the Config, zero values fall back to constants func (self *Config) init() { if self.BlockHashesBatchSize == 0 { self.BlockHashesBatchSize = blockHashesBatchSize @@ -106,6 +119,9 @@ func (self *Config) init() { if self.PeerSuspensionInterval == 0 { self.PeerSuspensionInterval = peerSuspensionInterval } + if self.StatusUpdateInterval == 0 { + self.StatusUpdateInterval = statusUpdateInterval + } } // node is the basic unit of the internal model of block chain/tree in the blockpool @@ -132,31 +148,35 @@ type entry struct { type BlockPool struct { Config *Config - // the minimal interface with blockchain - hasBlock func(hash common.Hash) bool - insertChain func(types.Blocks) error - verifyPoW func(pow.Block) bool - chainEvents *event.TypeMux + // the minimal interface with blockchain manager + hasBlock func(hash common.Hash) bool // query if block is known + insertChain func(types.Blocks) error // add section to blockchain + verifyPoW func(pow.Block) bool // soft PoW verification + chainEvents *event.TypeMux // ethereum eventer for chainEvents - tdSub event.Subscription - td *big.Int + tdSub event.Subscription // subscription to core.ChainHeadEvent + td *big.Int // our own total difficulty - pool map[string]*entry - peers *peers + pool map[string]*entry // the actual blockpool + peers *peers // peers manager in peers.go + + status *status // info about blockpool (UI interface) in status.go lock sync.RWMutex chainLock sync.RWMutex // alloc-easy pool of hash slices hashSlicePool chan []common.Hash - status *status - - quit chan bool - wg sync.WaitGroup - running bool + // waitgroup is used in tests to wait for result-critical routines + // as well as in determining idle / syncing status + wg sync.WaitGroup // + quit chan bool // chan used for quitting parallel routines + running bool // } // public constructor +// after blockpool returned, config can be set +// BlockPool.Start will call Config.init to set missing values func New( hasBlock func(hash common.Hash) bool, insertChain func(types.Blocks) error, @@ -175,15 +195,6 @@ func New( } } -func severity(code int) ethlogger.LogLevel { - switch code { - case ErrUnrequestedBlock: - return ethlogger.WarnLevel - default: - return ethlogger.ErrorLevel - } -} - // allows restart func (self *BlockPool) Start() { self.lock.Lock() @@ -193,7 +204,9 @@ func (self *BlockPool) Start() { return } + // set missing values self.Config.init() + self.hashSlicePool = make(chan []common.Hash, 150) self.status = newStatus() self.quit = make(chan bool) @@ -212,8 +225,11 @@ func (self *BlockPool) Start() { bp: self, } + // subscribe and listen to core.ChainHeadEvent{} for uptodate TD self.tdSub = self.chainEvents.Subscribe(core.ChainHeadEvent{}) - timer := time.NewTicker(3 * time.Second) + + // status update interval + timer := time.NewTicker(self.Config.StatusUpdateInterval) go func() { for { select { @@ -292,9 +308,14 @@ func (self *BlockPool) Wait(t time.Duration) { /* AddPeer is called by the eth protocol instance running on the peer after the status message has been received with total difficulty and current block hash -Called a second time with the same peer id, it is used to update chain info for a peer. This is used when a new (mined) block message is received. + +Called a second time with the same peer id, it is used to update chain info for a peer. +This is used when a new (mined) block message is received. + RemovePeer needs to be called when the peer disconnects. -Peer info is currently not persisted across disconnects (or sessions) + +Peer info is currently not persisted across disconnects (or sessions) except for suspension + */ func (self *BlockPool) AddPeer( @@ -319,12 +340,12 @@ AddBlockHashes Entry point for eth protocol to add block hashes received via BlockHashesMsg -only hashes from the best peer are handled +Only hashes from the best peer are handled -initiates further hash requests until a known parent is reached (unless cancelled by a peerSwitch event, i.e., when a better peer becomes best peer) -launches all block request processes on each chain section +Initiates further hash requests until a known parent is reached (unless cancelled by a peerSwitch event, i.e., when a better peer becomes best peer) +Launches all block request processes on each chain section -the first argument is an iterator function. Using this block hashes are decoded from the rlp message payload on demand. As a result, AddBlockHashes needs to run synchronously for one peer since the message is discarded if the caller thread returns. +The first argument is an iterator function. Using this block hashes are decoded from the rlp message payload on demand. As a result, AddBlockHashes needs to run synchronously for one peer since the message is discarded if the caller thread returns. */ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId string) { @@ -335,7 +356,6 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st // bestpeer is still the best peer self.wg.Add(1) - defer func() { self.wg.Done() }() self.status.lock.Lock() @@ -360,11 +380,11 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st return } /* - when peer is promoted in switchPeer, a new header section process is launched - as the head section skeleton is actually created here, it is signaled to the process - so that it can quit - in the special case that the node for parent of the head block is found in the blockpool - (with or without fetched block) + When peer is promoted in switchPeer, a new header section process is launched. + Once the head section skeleton is actually created here, it is signaled to the process + so that it can quit. + In the special case that the node for parent of the head block is found in the blockpool + (with or without fetched block), a singleton section containing only the head block node is created. */ headSection = true if entry := self.get(bestpeer.currentBlockHash); entry == nil { @@ -383,7 +403,7 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st } else { // otherwise set child section iff found node is the root of a section // this is a possible scenario when a singleton head section was created - // on an earlier occasion this peer or another with the same block was best peer + // on an earlier occasion when this peer or another with the same block was best peer if entry.node == entry.section.bottom { child = entry.section plog.DebugDetailf("AddBlockHashes: peer <%s>: connects to child section root %s", peerId, hex(bestpeer.currentBlockHash)) @@ -414,7 +434,7 @@ LOOP: default: } - // if we reach the blockchain we stop reading more + // if we reach the blockchain we stop reading further blockhashes if self.hasBlock(hash) { // check if known block connecting the downloaded chain to our blockchain plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s) found block %s in the blockchain", peerId, hex(bestpeer.currentBlockHash), hex(hash)) @@ -451,10 +471,11 @@ LOOP: // reached a known chain in the pool if entry.node == entry.section.bottom && n == 1 { /* - the first block hash received is an orphan in the pool - this also supports clients that (despite the spec) include hash in their + The first block hash received is an orphan node in the pool + + This also supports clients that (despite the spec) include hash in their response to hashes request. Note that by providing we can link sections - without having to wait for the root block of the child section to arrive, so it allows for superior performance + without having to wait for the root block of the child section to arrive, so it allows for superior performance. */ plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s) found head block [%s] as root of connecting child section [%s] skipping", peerId, hex(bestpeer.currentBlockHash), hex(hash), sectionhex(entry.section)) // record the entry's chain section as child section @@ -486,9 +507,8 @@ LOOP: plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s): %v nodes in new section", peerId, hex(bestpeer.currentBlockHash), len(nodes)) /* - handle forks where connecting node is mid-section - by splitting section at fork - no splitting needed if connecting node is head of a section + Handle forks where connecting node is mid-section by splitting section at fork. + No splitting needed if connecting node is head of a section. */ if parent != nil && entry != nil && entry.node != parent.top && len(nodes) > 0 { plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s): fork after %s", peerId, hex(bestpeer.currentBlockHash), hex(hash)) @@ -500,10 +520,7 @@ LOOP: self.status.lock.Unlock() } - /* - if new section is created, link it to parent/child sections - and launch section process fetching blocks and further hashes - */ + // If new section is created, link it to parent/child sections. sec = self.linkSections(nodes, parent, child) if sec != nil { @@ -516,11 +533,12 @@ LOOP: self.chainLock.Unlock() /* - if a blockpool node is reached (parent section is not nil), + If a blockpool node is reached (parent section is not nil), activate section (unless our peer is demoted by now). - this can be the bottom half of a newly split section in case of a fork. + This can be the bottom half of a newly split section in case of a fork. + bestPeer is nil if we got here after our peer got demoted while processing. - in this case no activation should happen + In this case no activation should happen */ if parent != nil && !peerswitch { self.activateChain(parent, bestpeer, nil) @@ -528,9 +546,8 @@ LOOP: } /* - if a new section was created, - register section iff head section or no child known - activate it with this peer + If a new section was created, register section iff head section or no child known + Activate it with this peer. */ if sec != nil { // switch on section process (it is paused by switchC) @@ -541,9 +558,9 @@ LOOP: bestpeer.lock.Unlock() } /* - request next block hashes for parent section here. - but only once, repeating only when bottom block arrives, - otherwise no way to check if it arrived + Request another batch of older block hashes for parent section here. + But only once, repeating only when the section's root block arrives. + Otherwise no way to check if it arrived. */ bestpeer.requestBlockHashes(sec.bottom.hash) plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s): start requesting blocks for section [%s]", peerId, hex(bestpeer.currentBlockHash), sectionhex(sec)) @@ -554,7 +571,7 @@ LOOP: } } - // if we are processing peer's head section, signal it to headSection process that it is created + // If we are processing peer's head section, signal it to headSection process that it is created. if headSection { plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s) head section registered on head section process", peerId, hex(bestpeer.currentBlockHash)) @@ -578,11 +595,13 @@ LOOP: /* AddBlock is the entry point for the eth protocol to call when blockMsg is received. - It has a strict interpretation of the protocol in that if the block received has not been requested, it results in an error + It has a strict interpretation of the protocol in that if the block received has not been requested, it results in an error. At the same time it is opportunistic in that if a requested block may be provided by any peer. The received block is checked for PoW. Only the first PoW-valid block for a hash is considered legit. + + If the block received is the head block of the current best peer, signal it to the head section process */ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { hash := block.Hash() @@ -611,6 +630,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { self.status.lock.Unlock() } else { plog.DebugDetailf("AddBlock: head block %s for peer <%s> (head: %s) already known", hex(hash), peerId, hex(sender.currentBlockHash)) + // signal to head section process sender.currentBlockC <- block } } else { @@ -629,7 +649,6 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { sender.lock.Unlock() if entry == nil { - // penalise peer for sending what we have not asked plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) sender.addError(ErrUnrequestedBlock, "%x", hash) @@ -647,7 +666,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { node.lock.Lock() defer node.lock.Unlock() - // check if block already present + // check if block already received if node.block != nil { plog.DebugDetailf("AddBlock: block %s from peer <%s> (head: %s) already sent by <%s> ", hex(hash), peerId, hex(sender.currentBlockHash), node.blockBy) return @@ -683,9 +702,9 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { } /* - iterates down a chain section by section - activating section process on incomplete sections with peer - relinking orphaned sections with their parent if root block (and its parent hash) is known) + activateChain iterates down a chain section by section. + It activates the section process on incomplete sections with peer. + It relinks orphaned sections with their parent if root block (and its parent hash) is known. */ func (self *BlockPool) activateChain(sec *section, p *peer, connected map[string]*section) { @@ -704,8 +723,8 @@ LOOP: connected[sec.top.hash.Str()] = sec } /* - we need to relink both complete and incomplete sections - the latter could have been blockHashesRequestsComplete before being delinked from its parent + Need to relink both complete and incomplete sections + An incomplete section could have been blockHashesRequestsComplete before being delinked from its parent. */ if parent == nil { if sec.bottom.block != nil { @@ -720,7 +739,7 @@ LOOP: } sec = parent - // stop if peer got demoted + // stop if peer got demoted or global quit select { case <-switchC: break LOOP @@ -731,6 +750,7 @@ LOOP: } } +// check if block's actual TD (calculated after successful insertChain) is identical to TD advertised for peer's head block. func (self *BlockPool) checkTD(nodes ...*node) { for _, n := range nodes { if n.td != nil { @@ -742,7 +762,7 @@ func (self *BlockPool) checkTD(nodes ...*node) { } } -// must run in separate go routine, otherwise +// requestBlocks must run in separate go routine, otherwise // switchpeer -> activateChain -> activate deadlocks on section process select and peers.lock func (self *BlockPool) requestBlocks(attempts int, hashes []common.Hash) { self.wg.Add(1) @@ -806,6 +826,7 @@ func (self *BlockPool) remove(sec *section) { } } +// get/put for optimised allocation similar to sync.Pool func (self *BlockPool) getHashSlice() (s []common.Hash) { select { case s = <-self.hashSlicePool: @@ -815,7 +836,6 @@ func (self *BlockPool) getHashSlice() (s []common.Hash) { return } -// Return returns a Client to the pool. func (self *BlockPool) putHashSlice(s []common.Hash) { if len(s) == self.Config.BlockBatchSize { select { diff --git a/blockpool/blockpool_test.go b/blockpool/blockpool_test.go index a76cab9b6..cd69d5104 100644 --- a/blockpool/blockpool_test.go +++ b/blockpool/blockpool_test.go @@ -9,6 +9,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) +// using the mock framework in blockpool_util_test +// we test various scenarios here + func TestPeerWithKnownBlock(t *testing.T) { test.LogInit() _, blockPool, blockPoolTester := newTestBlockPool(t) @@ -44,50 +47,6 @@ func TestPeerWithKnownParentBlock(t *testing.T) { blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain) } -func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) { - test.LogInit() - _, blockPool, blockPoolTester := newTestBlockPool(t) - blockPoolTester.blockChain[0] = nil - blockPoolTester.initRefBlockChain(4) - peer0 := blockPoolTester.newPeer("peer0", 2, 2) - peer1 := blockPoolTester.newPeer("peer1", 1, 1) - peer2 := blockPoolTester.newPeer("peer2", 4, 4) - - blockPool.Start() - blockPoolTester.tds = make(map[int]int) - blockPoolTester.tds[3] = 3 - - // pool - peer0.AddPeer() - peer0.serveBlocks(1, 2) - best := peer1.AddPeer() - // this tests that peer1 is not promoted over peer0 yet - if best { - t.Errorf("peer1 (TD=1) should not be set as best") - } - best = peer2.AddPeer() - peer2.serveBlocks(3, 4) - peer2.serveBlockHashes(4, 3, 2, 1) - hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3}) - peer1.waitBlocksRequests(3) - blockPool.AddBlock(&types.Block{ - HeaderHash: common.Hash(hashes[1]), - ParentHeaderHash: common.Hash(hashes[0]), - Td: common.Big3, - }, "peer1") - - blockPool.RemovePeer("peer2") - if blockPool.peers.best.id != "peer1" { - t.Errorf("peer1 (TD=3) should be set as best") - } - peer1.serveBlocks(0, 1, 2) - - blockPool.Wait(waitTimeout) - blockPool.Stop() - blockPoolTester.refBlockChain[4] = []int{} - blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain) -} - func TestSimpleChain(t *testing.T) { test.LogInit() _, blockPool, blockPoolTester := newTestBlockPool(t) @@ -166,6 +125,7 @@ func TestNewBlocksOnPartialChain(t *testing.T) { go peer1.serveBlocks(4, 5) // partially complete section go peer1.serveBlockHashes(5, 4, 3) peer1.serveBlocks(3, 4) // partially complete section + // peer1 found new blocks peer1.td = 7 peer1.currentBlock = 7 @@ -176,7 +136,6 @@ func TestNewBlocksOnPartialChain(t *testing.T) { go peer1.serveBlocks(5, 6) go peer1.serveBlockHashes(3, 2, 1) // tests that hash request from known chain root is remembered peer1.serveBlocks(0, 1, 2) - // blockPool.RemovePeer("peer1") blockPool.Wait(waitTimeout) blockPool.Stop() @@ -468,8 +427,8 @@ func TestForkCompleteSectionSwitchBackByPeerSwitchBack(t *testing.T) { peer1.AddPeer() go peer1.serveBlocks(8, 9) go peer1.serveBlockHashes(9, 8, 7) - peer1.serveBlocks(3, 7, 8) // make sure this section is complete - time.Sleep(1 * time.Second) + peer1.serveBlocks(3, 7, 8) // make sure this section is complete + time.Sleep(1 * time.Second) // go peer1.serveBlockHashes(7, 3, 2) // block 3/7 is section boundary peer1.serveBlocks(2, 3) // partially complete sections block 2 missing peer2.AddPeer() // @@ -477,8 +436,7 @@ func TestForkCompleteSectionSwitchBackByPeerSwitchBack(t *testing.T) { go peer2.serveBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3 peer2.serveBlocks(2, 3, 4, 5) // block 2 still missing. blockPool.RemovePeer("peer2") // peer2 disconnects, peer1 is promoted again as best peer - // peer1.serveBlockHashes(7, 3) // tests that hash request from fork root is remembered even though section process completed - go peer1.serveBlockHashes(2, 1, 0) // + go peer1.serveBlockHashes(2, 1, 0) // peer1.serveBlocks(0, 1, 2) blockPool.Wait(waitTimeout) diff --git a/blockpool/blockpool_util_test.go b/blockpool/blockpool_util_test.go index 02bb2422a..be14fbae8 100644 --- a/blockpool/blockpool_util_test.go +++ b/blockpool/blockpool_util_test.go @@ -66,7 +66,8 @@ func (self *blockPoolTester) Errorf(format string, params ...interface{}) { } // blockPoolTester implements the 3 callbacks needed by the blockPool: -// hasBlock, insetChain, verifyPoW +// hasBlock, insetChain, verifyPoW as well as provides the eventer +// to subscribe to head insertions func (self *blockPoolTester) hasBlock(block common.Hash) (ok bool) { self.lock.RLock() defer self.lock.RUnlock() @@ -77,6 +78,7 @@ func (self *blockPoolTester) hasBlock(block common.Hash) (ok bool) { return } +// mock insertChain relies on refBlockChain to determine block validity func (self *blockPoolTester) insertChain(blocks types.Blocks) error { self.lock.Lock() defer self.lock.Unlock() @@ -127,6 +129,7 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error { return nil } +// mock soft block validation always succeeds func (self *blockPoolTester) verifyPoW(pblock pow.Block) bool { return true } @@ -152,24 +155,24 @@ func (self *blockPoolTester) checkBlockChain(blockChain map[int][]int) { } } -// - // peerTester provides the peer callbacks for the blockPool // it registers actual callbacks so that the result can be compared to desired behaviour // provides helper functions to mock the protocol calls to the blockPool type peerTester struct { + // containers to record request and error callbacks blockHashesRequests []int blocksRequests [][]int blocksRequestsMap map[int]bool peerErrors []int - blockPool *BlockPool - hashPool *test.TestHashPool - lock sync.RWMutex - bt *blockPoolTester - id string - td int - currentBlock int - t *testing.T + + blockPool *BlockPool + hashPool *test.TestHashPool + lock sync.RWMutex + bt *blockPoolTester + id string + td int + currentBlock int + t *testing.T } // peerTester constructor takes hashPool and blockPool from the blockPoolTester @@ -222,6 +225,7 @@ func (self *peerTester) checkBlockHashesRequests(blocksHashesRequests ...int) { // waiter function used by peer.serveBlocks // blocking until requests appear +// this mocks proper wire protocol behaviour // since block requests are sent to any random peers // block request map is shared between peers // times out after waitTimeout @@ -254,6 +258,7 @@ func (self *peerTester) waitBlocksRequests(blocksRequest ...int) { // waiter function used by peer.serveBlockHashes // blocking until requests appear +// this mocks proper wire protocol behaviour // times out after a period func (self *peerTester) waitBlockHashesRequests(blocksHashesRequest int) { timeout := time.After(waitTimeout) @@ -299,6 +304,7 @@ func (self *peerTester) serveBlockHashes(indexes ...int) { self.sendBlockHashes(indexes...) } +// peer sends blockhashes not waiting for request func (self *peerTester) sendBlockHashes(indexes ...int) { // fmt.Printf("adding block hashes %v\n", indexes) hashes := self.hashPool.IndexesToHashes(indexes) @@ -315,13 +321,14 @@ func (self *peerTester) sendBlockHashes(indexes ...int) { } // peer sends blocks if and when there is a request -// (in the shared request store, not necessarily to a person) +// (in the shared request store, not necessarily to a specific peer) func (self *peerTester) serveBlocks(indexes ...int) { // fmt.Printf("ready to serve blocks %v\n", indexes[1:]) self.waitBlocksRequests(indexes[1:]...) self.sendBlocks(indexes...) } +// peer sends blocks not waiting for request func (self *peerTester) sendBlocks(indexes ...int) { // fmt.Printf("adding blocks %v \n", indexes) hashes := self.hashPool.IndexesToHashes(indexes) @@ -331,9 +338,10 @@ func (self *peerTester) sendBlocks(indexes ...int) { } } -// peer callbacks -// -1 is special: not found (a hash never seen) +// the 3 mock peer callbacks + // records block hashes requests by the blockPool +// -1 is special: not found (a hash never seen) func (self *peerTester) requestBlockHashes(hash common.Hash) error { indexes := self.hashPool.HashesToIndexes([]common.Hash{hash}) // fmt.Printf("[%s] block hash request %v %x\n", self.id, indexes[0], hash[:4]) diff --git a/blockpool/config_test.go b/blockpool/config_test.go index 2cb93769e..e1ce31f27 100644 --- a/blockpool/config_test.go +++ b/blockpool/config_test.go @@ -23,12 +23,13 @@ func TestBlockPoolConfig(t *testing.T) { test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t) test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, idleBestPeerTimeout, t) test.CheckDuration("PeerSuspensionInterval", c.PeerSuspensionInterval, peerSuspensionInterval, t) + test.CheckDuration("StatusUpdateInterval", c.StatusUpdateInterval, statusUpdateInterval, t) } func TestBlockPoolOverrideConfig(t *testing.T) { test.LogInit() blockPool := &BlockPool{Config: &Config{}, chainEvents: &event.TypeMux{}} - c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second, 30 * time.Second} + c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second, 30 * time.Second, 4 * time.Second} blockPool.Config = c blockPool.Start() @@ -42,4 +43,5 @@ func TestBlockPoolOverrideConfig(t *testing.T) { test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t) test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, 30*time.Second, t) test.CheckDuration("PeerSuspensionInterval", c.PeerSuspensionInterval, 30*time.Second, t) + test.CheckDuration("StatusUpdateInterval", c.StatusUpdateInterval, 4*time.Second, t) } diff --git a/blockpool/peers.go b/blockpool/peers.go index 5cc483a3b..1ace01fdf 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/errs" ) +// the blockpool's model of a peer type peer struct { lock sync.RWMutex @@ -104,12 +105,14 @@ func (self *peers) peerError(id string, code int, format string, params ...inter self.addToBlacklist(id) } +// record time of offence in blacklist to implement suspension for PeerSuspensionInterval func (self *peers) addToBlacklist(id string) { self.lock.Lock() defer self.lock.Unlock() self.blacklist[id] = time.Now() } +// suspended checks if peer is still suspended func (self *peers) suspended(id string) (s bool) { self.lock.Lock() defer self.lock.Unlock() @@ -160,8 +163,8 @@ func (self *peer) setChainInfoFromBlock(block *types.Block) { }() } +// distribute block request among known peers func (self *peers) requestBlocks(attempts int, hashes []common.Hash) { - // distribute block request among known peers self.lock.RLock() defer self.lock.RUnlock() peerCount := len(self.peers) @@ -196,7 +199,9 @@ func (self *peers) requestBlocks(attempts int, hashes []common.Hash) { } // addPeer implements the logic for blockpool.AddPeer -// returns true iff peer is promoted as best peer in the pool +// returns 2 bool values +// 1. true iff peer is promoted as best peer in the pool +// 2. true iff peer is still suspended func (self *peers) addPeer( td *big.Int, currentBlockHash common.Hash, @@ -214,10 +219,13 @@ func (self *peers) addPeer( self.lock.Lock() p, found := self.peers[id] if found { + // when called on an already connected peer, it means a newBlockMsg is received + // peer head info is updated if p.currentBlockHash != currentBlockHash { previousBlockHash = p.currentBlockHash plog.Debugf("addPeer: Update peer <%s> with td %v and current block %s (was %v)", id, td, hex(currentBlockHash), hex(previousBlockHash)) p.setChainInfo(td, currentBlockHash) + self.status.lock.Lock() self.status.values.NewBlocks++ self.status.lock.Unlock() @@ -235,7 +243,7 @@ func (self *peers) addPeer( } self.lock.Unlock() - // check peer current head + // check if peer's current head block is known if self.bp.hasBlock(currentBlockHash) { // peer not ahead plog.Debugf("addPeer: peer <%v> with td %v and current block %s is behind", id, td, hex(currentBlockHash)) @@ -255,6 +263,7 @@ func (self *peers) addPeer( } best = true } else { + // baseline is our own TD currentTD := self.bp.getTD() if self.best != nil { currentTD = self.best.td @@ -314,6 +323,7 @@ func (self *peers) removePeer(id string) { func (self *BlockPool) switchPeer(oldp, newp *peer) { // first quit AddBlockHashes, requestHeadSection and activateChain + // by closing the old peer's switchC channel if oldp != nil { plog.DebugDetailf("<%s> quit peer processes", oldp.id) close(oldp.switchC) @@ -366,11 +376,12 @@ func (self *BlockPool) switchPeer(oldp, newp *peer) { // newp activating section process changes the quit channel for this reason if oldp != nil { plog.DebugDetailf("<%s> quit section processes", oldp.id) - // close(oldp.idleC) } } +// getPeer looks up peer by id, returns peer and a bool value +// that is true iff peer is current best peer func (self *peers) getPeer(id string) (p *peer, best bool) { self.lock.RLock() defer self.lock.RUnlock() @@ -381,6 +392,8 @@ func (self *peers) getPeer(id string) (p *peer, best bool) { return } +// head section process + func (self *peer) handleSection(sec *section) { self.lock.Lock() defer self.lock.Unlock() @@ -516,7 +529,7 @@ func (self *peer) run() { LOOP: for { select { - // to minitor section process behaviou + // to minitor section process behaviour case <-ping.C: plog.Debugf("HeadSection: <%s> section with head %s, idle: %v", self.id, hex(self.currentBlockHash), self.idle) diff --git a/blockpool/peers_test.go b/blockpool/peers_test.go index db83de43a..0e4c40e87 100644 --- a/blockpool/peers_test.go +++ b/blockpool/peers_test.go @@ -142,3 +142,47 @@ func TestAddPeer(t *testing.T) { blockPool.Stop() } + +func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) { + test.LogInit() + _, blockPool, blockPoolTester := newTestBlockPool(t) + blockPoolTester.blockChain[0] = nil + blockPoolTester.initRefBlockChain(4) + peer0 := blockPoolTester.newPeer("peer0", 2, 2) + peer1 := blockPoolTester.newPeer("peer1", 1, 1) + peer2 := blockPoolTester.newPeer("peer2", 4, 4) + + blockPool.Start() + blockPoolTester.tds = make(map[int]int) + blockPoolTester.tds[3] = 3 + + // pool + peer0.AddPeer() + peer0.serveBlocks(1, 2) + best := peer1.AddPeer() + // this tests that peer1 is not promoted over peer0 yet + if best { + t.Errorf("peer1 (TD=1) should not be set as best") + } + best = peer2.AddPeer() + peer2.serveBlocks(3, 4) + peer2.serveBlockHashes(4, 3, 2, 1) + hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3}) + peer1.waitBlocksRequests(3) + blockPool.AddBlock(&types.Block{ + HeaderHash: common.Bytes(hashes[1]), + ParentHeaderHash: common.Bytes(hashes[0]), + Td: common.Big3, + }, "peer1") + + blockPool.RemovePeer("peer2") + if blockPool.peers.best.id != "peer1" { + t.Errorf("peer1 (TD=3) should be set as best") + } + peer1.serveBlocks(0, 1, 2) + + blockPool.Wait(waitTimeout) + blockPool.Stop() + blockPoolTester.refBlockChain[4] = []int{} + blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain) +} diff --git a/blockpool/test/hash_pool.go b/blockpool/test/hash_pool.go index eea135af1..df3c750f9 100644 --- a/blockpool/test/hash_pool.go +++ b/blockpool/test/hash_pool.go @@ -7,8 +7,12 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -// test helpers -// TODO: move into common test helper package (see p2p/crypto etc.) +// hashPool is a test helper, that allows random hashes to be referred to by integers +type TestHashPool struct { + intToHash + hashToInt + lock sync.Mutex +} func NewHashPool() *TestHashPool { return &TestHashPool{intToHash: make(intToHash), hashToInt: make(hashToInt)} @@ -18,13 +22,6 @@ type intToHash map[int]common.Hash type hashToInt map[common.Hash]int -// hashPool is a test helper, that allows random hashes to be referred to by integers -type TestHashPool struct { - intToHash - hashToInt - lock sync.Mutex -} - func newHash(i int) common.Hash { return common.BytesToHash(crypto.Sha3([]byte(string(i)))) } diff --git a/blockpool/test/logger.go b/blockpool/test/logger.go index 5d26151c1..bcb4d4cb3 100644 --- a/blockpool/test/logger.go +++ b/blockpool/test/logger.go @@ -9,6 +9,8 @@ import ( "github.com/ethereum/go-ethereum/logger" ) +// logging in tests + var once sync.Once /* usage: diff --git a/blockpool/test/util.go b/blockpool/test/util.go index e183bf1d1..0349493c3 100644 --- a/blockpool/test/util.go +++ b/blockpool/test/util.go @@ -6,6 +6,8 @@ import ( "time" ) +// miscellaneous test helpers + func CheckInt(name string, got int, expected int, t *testing.T) (err error) { if got != expected { t.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got) From 0578df9467bb00be967da7798cc0ea8b6e7e48d7 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 13:02:56 +0000 Subject: [PATCH 57/78] remove eth/wallet.go (only commented out content) --- eth/wallet.go | 80 --------------------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 eth/wallet.go diff --git a/eth/wallet.go b/eth/wallet.go deleted file mode 100644 index 9ec834309..000000000 --- a/eth/wallet.go +++ /dev/null @@ -1,80 +0,0 @@ -package eth - -/* -import ( - "crypto/ecdsa" - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" -) - -type Account struct { - w *Wallet -} - -func (self *Account) Transact(to *Account, value, gas, price *big.Int, data []byte) error { - return self.w.transact(self, to, value, gas, price, data) -} - -func (self *Account) Address() []byte { - return nil -} - -func (self *Account) PrivateKey() *ecdsa.PrivateKey { - return nil -} - -type Wallet struct{} - -func NewWallet() *Wallet { - return &Wallet{} -} - -func (self *Wallet) GetAccount(i int) *Account { -} - -func (self *Wallet) transact(from, to *Account, value, gas, price *big.Int, data []byte) error { - if from.PrivateKey() == nil { - return errors.New("accounts is not owned (no private key available)") - } - - var createsContract bool - if to == nil { - createsContract = true - } - - var msg *types.Transaction - if contractCreation { - msg = types.NewContractCreationTx(value, gas, price, data) - } else { - msg = types.NewTransactionMessage(to.Address(), value, gas, price, data) - } - - state := self.chainManager.TransState() - nonce := state.GetNonce(key.Address()) - - msg.SetNonce(nonce) - msg.SignECDSA(from.PriateKey()) - - // Do some pre processing for our "pre" events and hooks - block := self.chainManager.NewBlock(from.Address()) - coinbase := state.GetOrNewStateObject(from.Address()) - coinbase.SetGasPool(block.GasLimit()) - self.blockManager.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true) - - err := self.obj.TxPool().Add(tx) - if err != nil { - return nil, err - } - state.SetNonce(key.Address(), nonce+1) - - if contractCreation { - addr := core.AddressFromMessage(tx) - pipelogger.Infof("Contract addr %x\n", addr) - } - - return tx, nil -} -*/ From 8987750a369e4906f8d5301473cd4df8433177f3 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 15:02:50 +0000 Subject: [PATCH 58/78] fix import in reorganised test --- blockpool/blockpool_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/blockpool/blockpool_test.go b/blockpool/blockpool_test.go index cd69d5104..9bcd72f04 100644 --- a/blockpool/blockpool_test.go +++ b/blockpool/blockpool_test.go @@ -5,8 +5,6 @@ import ( "time" "github.com/ethereum/go-ethereum/blockpool/test" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" ) // using the mock framework in blockpool_util_test From d7564a9a25c06f0c9ad9440f02b09e20e0ca30bc Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 19 Mar 2015 23:33:52 +0000 Subject: [PATCH 59/78] fix common.Hash conversion --- blockpool/peers.go | 2 ++ blockpool/peers_test.go | 4 ++-- blockpool/section.go | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/blockpool/peers.go b/blockpool/peers.go index 1ace01fdf..80168b206 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" ) @@ -471,6 +472,7 @@ func (self *peer) getBlockHashes() { } } headKey := self.parentHash.Str() + height := self.bp.status.chain[headKey] + 1 self.bp.status.chain[self.currentBlockHash.Str()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height diff --git a/blockpool/peers_test.go b/blockpool/peers_test.go index 0e4c40e87..beeb0ad1d 100644 --- a/blockpool/peers_test.go +++ b/blockpool/peers_test.go @@ -170,8 +170,8 @@ func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) { hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3}) peer1.waitBlocksRequests(3) blockPool.AddBlock(&types.Block{ - HeaderHash: common.Bytes(hashes[1]), - ParentHeaderHash: common.Bytes(hashes[0]), + HeaderHash: common.Hash(hashes[1]), + ParentHeaderHash: common.Hash(hashes[0]), Td: common.Big3, }, "peer1") diff --git a/blockpool/section.go b/blockpool/section.go index 0304c9a04..18a27377d 100644 --- a/blockpool/section.go +++ b/blockpool/section.go @@ -117,7 +117,7 @@ func (self *section) addSectionToBlockChain(p *peer) { break } self.poolRootIndex-- - keys = append(keys, node.hash.Str()) + keys = append(keys, n.hash.Str()) blocks = append(blocks, block) nodes = append(nodes, n) } From 66b29899c474abeab6c66060c9ea5bbff85b9efb Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 20 Mar 2015 11:57:47 +0000 Subject: [PATCH 60/78] use common.Hash as pool key, no string conversion needed --- blockpool/blockpool.go | 12 ++++++------ blockpool/section.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index 921d34949..09b9e7b0b 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -157,8 +157,8 @@ type BlockPool struct { tdSub event.Subscription // subscription to core.ChainHeadEvent td *big.Int // our own total difficulty - pool map[string]*entry // the actual blockpool - peers *peers // peers manager in peers.go + pool map[common.Hash]*entry // the actual blockpool + peers *peers // peers manager in peers.go status *status // info about blockpool (UI interface) in status.go @@ -210,7 +210,7 @@ func (self *BlockPool) Start() { self.hashSlicePool = make(chan []common.Hash, 150) self.status = newStatus() self.quit = make(chan bool) - self.pool = make(map[string]*entry) + self.pool = make(map[common.Hash]*entry) self.running = true self.peers = &peers{ @@ -789,13 +789,13 @@ func (self *BlockPool) getChild(sec *section) *section { func (self *BlockPool) get(hash common.Hash) *entry { self.lock.RLock() defer self.lock.RUnlock() - return self.pool[hash.Str()] + return self.pool[hash] } func (self *BlockPool) set(hash common.Hash, e *entry) { self.lock.Lock() defer self.lock.Unlock() - self.pool[hash.Str()] = e + self.pool[hash] = e } // accessor and setter for total difficulty @@ -817,7 +817,7 @@ func (self *BlockPool) remove(sec *section) { defer self.lock.Unlock() for _, node := range sec.nodes { - delete(self.pool, node.hash.Str()) + delete(self.pool, node.hash) } if sec.initialised && sec.poolRootIndex != 0 { self.status.lock.Lock() diff --git a/blockpool/section.go b/blockpool/section.go index 18a27377d..bcbd71cfc 100644 --- a/blockpool/section.go +++ b/blockpool/section.go @@ -106,7 +106,7 @@ func (self *section) addSectionToBlockChain(p *peer) { var nodes []*node var n *node - var keys []string + var keys []common.Hash var blocks []*types.Block for self.poolRootIndex > 0 { n = self.nodes[self.poolRootIndex-1] @@ -117,7 +117,7 @@ func (self *section) addSectionToBlockChain(p *peer) { break } self.poolRootIndex-- - keys = append(keys, n.hash.Str()) + keys = append(keys, n.hash) blocks = append(blocks, block) nodes = append(nodes, n) } From c388e7eac0d26f4d299523fd14ec350655f66879 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Mar 2015 13:36:52 +0100 Subject: [PATCH 61/78] crypto: remove use of common.Value.Encode This seems to be the last remaining use of it. --- crypto/keypair.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/crypto/keypair.go b/crypto/keypair.go index 6702e6595..cc17328cb 100644 --- a/crypto/keypair.go +++ b/crypto/keypair.go @@ -3,8 +3,8 @@ package crypto import ( "strings" - "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) type KeyPair struct { @@ -48,11 +48,3 @@ func (k *KeyPair) Mnemonic() string { func (k *KeyPair) AsStrings() (string, string, string, string) { return k.Mnemonic(), common.Bytes2Hex(k.Address()), common.Bytes2Hex(k.PrivateKey), common.Bytes2Hex(k.PublicKey) } - -func (k *KeyPair) RlpEncode() []byte { - return k.RlpValue().Encode() -} - -func (k *KeyPair) RlpValue() *common.Value { - return common.NewValue(k.PrivateKey) -} From f7d1d601e92d3498f0fab5e80e5825d71f5d48fb Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Mar 2015 11:45:45 +0100 Subject: [PATCH 62/78] common: make Value encodable with package rlp Value.{Encode,Decode} are gone. It implements rlp.Encoder and rlp.Decoder instead, so Value can be decoded into directly. --- common/rlp_test.go | 28 +++++++++++--------- common/value.go | 65 +++++++++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/common/rlp_test.go b/common/rlp_test.go index 16a3553d7..2a55da928 100644 --- a/common/rlp_test.go +++ b/common/rlp_test.go @@ -5,6 +5,8 @@ import ( "math/big" "reflect" "testing" + + "github.com/ethereum/go-ethereum/rlp" ) func TestNonInterfaceSlice(t *testing.T) { @@ -19,13 +21,16 @@ func TestNonInterfaceSlice(t *testing.T) { func TestRlpValueEncoding(t *testing.T) { val := EmptyValue() - val.AppendList().Append(1).Append(2).Append(3) - val.Append("4").AppendList().Append(5) + val.AppendList().Append(byte(1)).Append(byte(2)).Append(byte(3)) + val.Append("4").AppendList().Append(byte(5)) - res := val.Encode() + res, err := rlp.EncodeToBytes(val) + if err != nil { + t.Fatalf("encode error: %v", err) + } exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}}) if bytes.Compare(res, exp) != 0 { - t.Errorf("expected %q, got %q", res, exp) + t.Errorf("expected %x, got %x", exp, res) } } @@ -57,9 +62,7 @@ func TestValueSlice(t *testing.T) { func TestLargeData(t *testing.T) { data := make([]byte, 100000) enc := Encode(data) - value := NewValue(enc) - value.Decode() - + value := NewValueFromBytes(enc) if value.Len() != len(data) { t.Error("Expected data to be", len(data), "got", value.Len()) } @@ -133,15 +136,16 @@ func TestEncodeDecodeBigInt(t *testing.T) { } func TestEncodeDecodeBytes(t *testing.T) { - b := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, byte(6)}) - val := NewValueFromBytes(b.Encode()) - if !b.Cmp(val) { - t.Errorf("Expected %v, got %v", val, b) + bv := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, []byte{6}}) + b, _ := rlp.EncodeToBytes(bv) + val := NewValueFromBytes(b) + if !bv.Cmp(val) { + t.Errorf("Expected %#v, got %#v", bv, val) } } func TestEncodeZero(t *testing.T) { - b := NewValue(0).Encode() + b, _ := rlp.EncodeToBytes(NewValue(0)) exp := []byte{0xc0} if bytes.Compare(b, exp) == 0 { t.Error("Expected", exp, "got", b) diff --git a/common/value.go b/common/value.go index 72a123772..f6150cb82 100644 --- a/common/value.go +++ b/common/value.go @@ -3,14 +3,29 @@ package common import ( "bytes" "fmt" + "io" "math/big" "reflect" "strconv" + + "github.com/ethereum/go-ethereum/rlp" ) -// Data values are returned by the rlp decoder. The data values represents -// one item within the rlp data structure. It's responsible for all the casting -// It always returns something valid +// Value can hold values of certain basic types and provides ways to +// convert between types without bothering to check whether the +// conversion is actually meaningful. +// +// It currently supports the following types: +// +// - int{,8,16,32,64} +// - uint{,8,16,32,64} +// - *big.Int +// - []byte, string +// - []interface{} +// +// Value is useful whenever you feel that Go's types limit your +// ability to express yourself. In these situations, use Value and +// forget about this strong typing nonsense. type Value struct { Val interface{} kind reflect.Value @@ -260,26 +275,34 @@ func (self *Value) DeepCmp(o *Value) bool { return bytes.Compare(self.Bytes(), o.Bytes()) == 0 } -func (val *Value) Encode() []byte { - return Encode(val.Val) -} - -// Assume that the data we have is encoded -func (self *Value) Decode() { - v, _ := Decode(self.Bytes(), 0) - self.Val = v - //self.Val = DecodeWithReader(bytes.NewBuffer(self.Bytes())) -} - -func NewValueFromBytes(data []byte) *Value { - if len(data) != 0 { - value := NewValue(data) - value.Decode() - - return value +func (self *Value) DecodeRLP(s *rlp.Stream) error { + var v interface{} + if err := s.Decode(&v); err != nil { + return err } + self.Val = v + return nil +} - return NewValue(nil) +func (self *Value) EncodeRLP(w io.Writer) error { + if self == nil { + w.Write(rlp.EmptyList) + return nil + } else { + return rlp.Encode(w, self.Val) + } +} + +// NewValueFromBytes decodes RLP data. +// The contained value will be nil if data contains invalid RLP. +func NewValueFromBytes(data []byte) *Value { + v := new(Value) + if len(data) != 0 { + if err := rlp.DecodeBytes(data, v); err != nil { + v.Val = nil + } + } + return v } // Value setters From dcb9614dfec3c8dcaaa47e9fa516528fdc47279b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Mar 2015 11:48:40 +0100 Subject: [PATCH 63/78] common: drop unused kind field from Value This makes Value 24 bytes smaller on 64bit systems. --- common/value.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/common/value.go b/common/value.go index f6150cb82..722e641b5 100644 --- a/common/value.go +++ b/common/value.go @@ -26,10 +26,7 @@ import ( // Value is useful whenever you feel that Go's types limit your // ability to express yourself. In these situations, use Value and // forget about this strong typing nonsense. -type Value struct { - Val interface{} - kind reflect.Value -} +type Value struct{ Val interface{} } func (val *Value) String() string { return fmt.Sprintf("%x", val.Val) @@ -53,7 +50,6 @@ func (val *Value) IsNil() bool { } func (val *Value) Len() int { - //return val.kind.Len() if data, ok := val.Val.([]interface{}); ok { return len(data) } From c161d73d429ef421cdb9c75b743c16d72aa8a89a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Mar 2015 13:33:11 +0100 Subject: [PATCH 64/78] common: drop accessors for Value.Val I don't see why we would need two different accessors for a public field. --- common/rlp.go | 2 +- common/value.go | 8 -------- common/value_test.go | 2 +- ethdb/memory_database.go | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/common/rlp.go b/common/rlp.go index 602f13202..06ac410e9 100644 --- a/common/rlp.go +++ b/common/rlp.go @@ -112,7 +112,7 @@ func Encode(object interface{}) []byte { if object != nil { switch t := object.(type) { case *Value: - buff.Write(Encode(t.Raw())) + buff.Write(Encode(t.Val)) case RlpEncodable: buff.Write(Encode(t.RlpData())) // Code dup :-/ diff --git a/common/value.go b/common/value.go index 722e641b5..c3893d565 100644 --- a/common/value.go +++ b/common/value.go @@ -57,14 +57,6 @@ func (val *Value) Len() int { return len(val.Bytes()) } -func (val *Value) Raw() interface{} { - return val.Val -} - -func (val *Value) Interface() interface{} { - return val.Val -} - func (val *Value) Uint() uint64 { if Val, ok := val.Val.(uint8); ok { return uint64(Val) diff --git a/common/value_test.go b/common/value_test.go index 09d37802d..38a0e9843 100644 --- a/common/value_test.go +++ b/common/value_test.go @@ -35,7 +35,7 @@ func (s *ValueSuite) TestValueTypes(c *checker.C) { c.Assert(str.Str(), checker.Equals, strExp) c.Assert(num.Uint(), checker.Equals, numExp) - c.Assert(NewValue(inter.Interface()).Cmp(NewValue(interExp)), checker.Equals, true) + c.Assert(NewValue(inter.Val).Cmp(NewValue(interExp)), checker.Equals, true) c.Assert(byt.Bytes(), checker.DeepEquals, bytExp) c.Assert(bigInt.BigInt(), checker.DeepEquals, bigExp) } diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index d914f47f8..d4988d0d8 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -49,7 +49,7 @@ func (db *MemDatabase) Print() { for key, val := range db.db { fmt.Printf("%x(%d): ", key, len(key)) node := common.NewValueFromBytes(val) - fmt.Printf("%q\n", node.Interface()) + fmt.Printf("%q\n", node.Val) } } From deee9cb170ff105992ede83c52013d0c2c4ad10d Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Mar 2015 15:54:42 +0100 Subject: [PATCH 65/78] Added caching for block chain. Currently set to 10k --- core/block_cache.go | 68 ++++++++++++++++++++++++++++++++++++++ core/block_cache_test.go | 48 +++++++++++++++++++++++++++ core/chain_manager.go | 20 ++++++++++- core/chain_manager_test.go | 2 +- 4 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 core/block_cache.go create mode 100644 core/block_cache_test.go diff --git a/core/block_cache.go b/core/block_cache.go new file mode 100644 index 000000000..321021eb4 --- /dev/null +++ b/core/block_cache.go @@ -0,0 +1,68 @@ +package core + +import ( + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// BlockCache implements a caching mechanism specifically for blocks and uses FILO to pop +type BlockCache struct { + size int + + hashes []common.Hash + blocks map[common.Hash]*types.Block + + mu sync.RWMutex +} + +// Creates and returns a `BlockCache` with `size`. If `size` is smaller than 1 it will panic +func NewBlockCache(size int) *BlockCache { + if size < 1 { + panic("block cache size not allowed to be smaller than 1") + } + + bc := &BlockCache{size: size} + bc.Clear() + return bc +} + +func (bc *BlockCache) Clear() { + bc.blocks = make(map[common.Hash]*types.Block) + bc.hashes = nil + +} + +func (bc *BlockCache) Push(block *types.Block) { + bc.mu.Lock() + defer bc.mu.Unlock() + + if len(bc.hashes) == bc.size { + delete(bc.blocks, bc.hashes[0]) + + // XXX There are a few other options on solving this + // 1) use a poller / GC like mechanism to clean up untracked objects + // 2) copy as below + // re-use the slice and remove the reference to bc.hashes[0] + // this will allow the element to be garbage collected. + copy(bc.hashes, bc.hashes[1:]) + } else { + bc.hashes = append(bc.hashes, common.Hash{}) + } + + hash := block.Hash() + bc.blocks[hash] = block + bc.hashes[len(bc.hashes)-1] = hash +} + +func (bc *BlockCache) Get(hash common.Hash) *types.Block { + bc.mu.RLock() + defer bc.mu.RUnlock() + + if block, haz := bc.blocks[hash]; haz { + return block + } + + return nil +} diff --git a/core/block_cache_test.go b/core/block_cache_test.go new file mode 100644 index 000000000..d4f610b71 --- /dev/null +++ b/core/block_cache_test.go @@ -0,0 +1,48 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +func newChain(size int) (chain []*types.Block) { + var parentHash common.Hash + for i := 0; i < size; i++ { + block := types.NewBlock(parentHash, common.Address{}, common.Hash{}, new(big.Int), 0, "") + block.Header().Number = big.NewInt(int64(i)) + chain = append(chain, block) + parentHash = block.Hash() + } + return +} + +func insertChainCache(cache *BlockCache, chain []*types.Block) { + for _, block := range chain { + cache.Push(block) + } +} + +func TestNewBlockCache(t *testing.T) { + chain := newChain(3) + cache := NewBlockCache(2) + insertChainCache(cache, chain) + + if cache.hashes[0] != chain[1].Hash() { + t.Error("oldest block incorrect") + } +} + +func TestInclusion(t *testing.T) { + chain := newChain(3) + cache := NewBlockCache(3) + insertChainCache(cache, chain) + + for _, block := range chain { + if b := cache.Get(block.Hash()); b == nil { + t.Errorf("getting %x failed", block.Hash()) + } + } +} diff --git a/core/chain_manager.go b/core/chain_manager.go index 915fa704f..1bc8edea6 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -23,6 +23,8 @@ var ( blockNumPre = []byte("block-num-") ) +const blockCacheLimit = 10000 + type StateQuery interface { GetAccount(addr []byte) *state.StateObject } @@ -92,15 +94,25 @@ type ChainManager struct { transState *state.StateDB txState *state.ManagedState + cache *BlockCache + quit chan struct{} } func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *ChainManager { - bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{})} + bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{}), cache: NewBlockCache(blockCacheLimit)} bc.setLastBlock() bc.transState = bc.State().Copy() // Take ownership of this particular state bc.txState = state.ManageState(bc.State().Copy()) + + // load in last `blockCacheLimit` - 1 blocks. Last block is the current. + ancestors := bc.GetAncestors(bc.currentBlock, blockCacheLimit-1) + ancestors = append(ancestors, bc.currentBlock) + for _, block := range ancestors { + bc.cache.Push(block) + } + go bc.update() return bc @@ -275,6 +287,8 @@ func (bc *ChainManager) insert(block *types.Block) { key := append(blockNumPre, block.Number().Bytes()...) bc.blockDb.Put(key, bc.lastBlockHash.Bytes()) + // Push block to cache + bc.cache.Push(block) } func (bc *ChainManager) write(block *types.Block) { @@ -318,6 +332,10 @@ func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) ( } func (self *ChainManager) GetBlock(hash common.Hash) *types.Block { + if block := self.cache.Get(hash); block != nil { + return block + } + data, _ := self.blockDb.Get(append(blockHashPre, hash[:]...)) if len(data) == 0 { return nil diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index e49e594a3..bf172f3bf 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -69,7 +69,7 @@ func printChain(bc *ChainManager) { func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) { td := new(big.Int) for _, block := range chainB { - td2, err := bman.bc.processor.Process(block) + td2, _, err := bman.bc.processor.Process(block) if err != nil { if IsKnownBlockErr(err) { continue From 54dac59285ccc6a3af47201479ca556da2899e93 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Mar 2015 17:42:09 +0100 Subject: [PATCH 66/78] wip --- eth/backend.go | 2 +- miner/agent.go | 4 ++++ miner/worker.go | 4 ++-- rpc/api.go | 8 ++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index afe314d74..52f336c1d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -205,7 +205,7 @@ func New(config *Config) (*Ethereum, error) { ethProto := EthProtocol(config.ProtocolVersion, config.NetworkId, eth.txPool, eth.chainManager, eth.blockPool) protocols := []p2p.Protocol{ethProto} if config.Shh { - protocols = append(protocols, eth.whisper.Protocol()) + //protocols = append(protocols, eth.whisper.Protocol()) } eth.net = &p2p.Server{ diff --git a/miner/agent.go b/miner/agent.go index 6865d5a08..64491e04c 100644 --- a/miner/agent.go +++ b/miner/agent.go @@ -79,3 +79,7 @@ func (self *CpuMiner) mine(block *types.Block) { self.returnCh <- Work{block.Number().Uint64(), nonce, mixDigest, seedHash} } } + +func (self *CpuMiner) GetHashRate() int64 { + return self.pow.GetHashrate() +} diff --git a/miner/worker.go b/miner/worker.go index 63d1bfa0b..ae6782aca 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -57,7 +57,7 @@ type Agent interface { SetWorkCh(chan<- Work) Stop() Start() - Pow() pow.PoW + GetHashRate() int64 } type worker struct { @@ -272,7 +272,7 @@ func (self *worker) commitTransaction(tx *types.Transaction) error { func (self *worker) HashRate() int64 { var tot int64 for _, agent := range self.agents { - tot += agent.Pow().GetHashrate() + tot += agent.GetHashRate() } return tot diff --git a/rpc/api.go b/rpc/api.go index 659bc373d..34d4ff0fc 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -488,3 +488,11 @@ func toFilterOptions(options *BlockFilterArgs) *core.FilterOptions { return &opts } + +/* + Work() chan<- *types.Block + SetWorkCh(chan<- Work) + Stop() + Start() + Rate() uint64 +*/ From ecd10d2cf765072cd74347b9e0ca2bb85091450f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Mar 2015 18:00:54 +0100 Subject: [PATCH 67/78] iterator returned wrong value --- eth/protocol.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eth/protocol.go b/eth/protocol.go index 1999d9807..494c1c1bb 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -213,8 +213,7 @@ func (self *ethProtocol) handle() error { var i int iter := func() (hash common.Hash, ok bool) { - var h common.Hash - err := msgStream.Decode(&h) + err := msgStream.Decode(&hash) if err == rlp.EOL { return common.Hash{}, false } else if err != nil { From abce6804a085087770be587e039fd4669d5eac26 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Mar 2015 20:37:56 +0100 Subject: [PATCH 68/78] Right pad bytes to prevent future programmers making bugs --- vm/memory.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/vm/memory.go b/vm/memory.go index 2a1e6e1b9..dd47fa1b5 100644 --- a/vm/memory.go +++ b/vm/memory.go @@ -1,6 +1,10 @@ package vm -import "fmt" +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) type Memory struct { store []byte @@ -11,21 +15,21 @@ func NewMemory() *Memory { } func (m *Memory) Set(offset, size uint64, value []byte) { - if len(value) > 0 { - totSize := offset + size - lenSize := uint64(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...) - } + value = common.RightPadBytes(value, int(size)) + + totSize := offset + size + lenSize := uint64(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) } + copy(m.store[offset:offset+size], value) } func (m *Memory) Resize(size uint64) { From b41185a68f2ec8c492a7dbec1a6bf65f29b0843a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Mar 2015 22:33:40 +0100 Subject: [PATCH 69/78] rlp: fix nil pointer decoding The generic pointer decoder did not advance the input position for empty values. This can lead to strange issues and even infinite loops. --- rlp/decode.go | 7 ++++++- rlp/decode_test.go | 22 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/rlp/decode.go b/rlp/decode.go index 6d7e670c2..0e99d9caa 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -367,7 +367,12 @@ func makePtrDecoder(typ reflect.Type) (decoder, error) { dec := func(s *Stream, val reflect.Value) (err error) { _, size, err := s.Kind() if err != nil || size == 0 && s.byteval == 0 { - val.Set(reflect.Zero(typ)) // set to nil + // rearm s.Kind. This is important because the input + // position must advance to the next value even though + // we don't read anything. + s.kind = -1 + // set the pointer to nil. + val.Set(reflect.Zero(typ)) return err } newval := val diff --git a/rlp/decode_test.go b/rlp/decode_test.go index 9f66840b1..0f034d5d8 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -39,7 +39,7 @@ func TestStreamKind(t *testing.T) { s := NewStream(bytes.NewReader(unhex(test.input))) kind, len, err := s.Kind() if err != nil { - t.Errorf("test %d: Type returned error: %v", i, err) + t.Errorf("test %d: Kind returned error: %v", i, err) continue } if kind != test.wantKind { @@ -93,6 +93,23 @@ func TestStreamErrors(t *testing.T) { {"C3C2010201", calls{"List", "List", "Uint", "Uint", "ListEnd", "Uint"}, EOL}, {"00", calls{"ListEnd"}, errNotInList}, {"C40102", calls{"List", "Uint", "ListEnd"}, errNotAtEOL}, + + // This test verifies that the input position is advanced + // correctly when calling Bytes for empty strings. Kind can be called + // any number of times in between and doesn't advance. + {"C3808080", calls{ + "List", // enter the list + "Bytes", // past first element + + "Kind", "Kind", "Kind", // this shouldn't advance + + "Bytes", // past second element + + "Kind", "Kind", // can't hurt to try + + "Bytes", // past final element + "Bytes", // this one should fail + }, EOL}, } testfor: @@ -314,6 +331,9 @@ var decodeTests = []decodeTest{ {input: "C109", ptr: new(*[]uint), value: &[]uint{9}}, {input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}}, + // check that input position is advanced also empty values. + {input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}}, + // pointer should be reset to nil {input: "05", ptr: sharedPtr, value: uintp(5)}, {input: "80", ptr: sharedPtr, value: (*uint)(nil)}, From b95ff54632d9a31286f5b629556071b6043d274a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Mar 2015 22:46:41 +0100 Subject: [PATCH 70/78] cmd/blocktest: delete package Blocktests are now integrated in cmd/ethereum. --- cmd/blocktest/main.go | 213 ------------------------------------------ 1 file changed, 213 deletions(-) delete mode 100644 cmd/blocktest/main.go diff --git a/cmd/blocktest/main.go b/cmd/blocktest/main.go deleted file mode 100644 index acbadee77..000000000 --- a/cmd/blocktest/main.go +++ /dev/null @@ -1,213 +0,0 @@ -/* - This file is part of go-ethereum - - go-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - go-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with go-ethereum. If not, see . -*/ -/** - * @authors - * Gustav Simonsson - * @date 2015 - * - */ - -package main - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "log" - "math/big" - "os" - "runtime" - "strings" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/core" - types "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/rlp" -) - -type Account struct { - Balance string - Code string - Nonce string - Storage map[string]string -} - -type BlockHeader struct { - Bloom string - Coinbase string - Difficulty string - ExtraData string - GasLimit string - GasUsed string - MixHash string - Nonce string - Number string - ParentHash string - ReceiptTrie string - SeedHash string - StateRoot string - Timestamp string - TransactionsTrie string - UncleHash string -} - -type Tx struct { - Data string - GasLimit string - GasPrice string - Nonce string - R string - S string - To string - V string - Value string -} - -type Block struct { - BlockHeader BlockHeader - Rlp string - Transactions []Tx - UncleHeaders []string -} - -type Test struct { - Blocks []Block - GenesisBlockHeader BlockHeader - Pre map[string]Account -} - -func main() { - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "%s \n", os.Args[0]) - flag.PrintDefaults() - } - flag.Parse() - - runtime.GOMAXPROCS(runtime.NumCPU()) - logger.AddLogSystem(logger.NewStdLogSystem(os.Stderr, log.LstdFlags, logger.DebugDetailLevel)) - defer func() { logger.Flush() }() - - if len(os.Args) < 2 { - utils.Fatalf("Please specify a test file as the first argument.") - } - blocks, err := loadBlocksFromTestFile(os.Args[1]) - if err != nil { - utils.Fatalf("Could not load blocks: %v", err) - } - - chain := memchain() - chain.ResetWithGenesisBlock(blocks[0]) - if err = chain.InsertChain(types.Blocks{blocks[1]}); err != nil { - utils.Fatalf("Error: %v", err) - } else { - fmt.Println("PASS") - } -} - -func memchain() *core.ChainManager { - blockdb, err := ethdb.NewMemDatabase() - if err != nil { - utils.Fatalf("Could not create in-memory database: %v", err) - } - statedb, err := ethdb.NewMemDatabase() - if err != nil { - utils.Fatalf("Could not create in-memory database: %v", err) - } - return core.NewChainManager(blockdb, statedb, new(event.TypeMux)) -} - -func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) { - fileContent, err := ioutil.ReadFile(filePath) - if err != nil { - return - } - bt := make(map[string]Test) - if err = json.Unmarshal(fileContent, &bt); err != nil { - return - } - - // TODO: support multiple blocks; loop over all blocks - gbh := new(types.Header) - - // Let's use slighlty different namings for the same things, because that's awesome. - gbh.ParentHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.ParentHash) - gbh.UncleHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.UncleHash) - gbh.Coinbase, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.Coinbase) - gbh.Root, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.StateRoot) - gbh.TxHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.TransactionsTrie) - gbh.ReceiptHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.ReceiptTrie) - gbh.Bloom, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.Bloom) - - gbh.MixDigest, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.MixHash) - //gbh.SeedHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.SeedHash) - - d, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Difficulty, 10) - gbh.Difficulty = d - - n, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Number, 10) - gbh.Number = n - - gl, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.GasLimit, 10) - gbh.GasLimit = gl - - gu, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.GasUsed, 10) - gbh.GasUsed = gu - - ts, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Timestamp, 0) - gbh.Time = ts.Uint64() - - extra, err := hex_decode(bt["SimpleTx"].GenesisBlockHeader.ExtraData) - gbh.Extra = string(extra) // TODO: change ExtraData to byte array - - nonce, _ := hex_decode(bt["SimpleTx"].GenesisBlockHeader.Nonce) - gbh.Nonce = nonce - - if err != nil { - return - } - - gb := types.NewBlockWithHeader(gbh) - //gb.uncles = *new([]*types.Header) - //gb.transactions = *new(types.Transactions) - gb.Td = new(big.Int) - gb.Reward = new(big.Int) - - testBlock := new(types.Block) - - rlpBytes, err := hex_decode(bt["SimpleTx"].Blocks[0].Rlp) - err = rlp.Decode(bytes.NewReader(rlpBytes), &testBlock) - if err != nil { - return - } - - blocks = types.Blocks{ - gb, - testBlock, - } - - return -} - -func hex_decode(s string) (res []byte, err error) { - return hex.DecodeString(strings.TrimPrefix(s, "0x")) -} From a829a5658723ff3681f14650818ef050cb0a7fa8 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 21 Mar 2015 00:49:31 +0100 Subject: [PATCH 71/78] rlp: add Stream.Raw --- rlp/decode.go | 25 +++++++++++++++++++++++++ rlp/decode_test.go | 16 +++++++++++++++- rlp/encode.go | 32 ++++++++++++++++++++------------ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/rlp/decode.go b/rlp/decode.go index 0e99d9caa..0fde0a947 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -540,6 +540,31 @@ func (s *Stream) Bytes() ([]byte, error) { } } +// Raw reads a raw encoded value including RLP type information. +func (s *Stream) Raw() ([]byte, error) { + kind, size, err := s.Kind() + if err != nil { + return nil, err + } + if kind == Byte { + s.kind = -1 // rearm Kind + return []byte{s.byteval}, nil + } + // the original header has already been read and is no longer + // available. read content and put a new header in front of it. + start := headsize(size) + buf := make([]byte, uint64(start)+size) + if err := s.readFull(buf[start:]); err != nil { + return nil, err + } + if kind == String { + puthead(buf, 0x80, 0xB8, size) + } else { + puthead(buf, 0xC0, 0xF7, size) + } + return buf, nil +} + var errUintOverflow = errors.New("rlp: uint overflow") // Uint reads an RLP string of up to 8 bytes and returns its contents diff --git a/rlp/decode_test.go b/rlp/decode_test.go index 0f034d5d8..a18ff1d08 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -165,6 +165,20 @@ func TestStreamList(t *testing.T) { } } +func TestStreamRaw(t *testing.T) { + s := NewStream(bytes.NewReader(unhex("C58401010101"))) + s.List() + + want := unhex("8401010101") + raw, err := s.Raw() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(want, raw) { + t.Errorf("raw mismatch: got %x, want %x", raw, want) + } +} + func TestDecodeErrors(t *testing.T) { r := bytes.NewReader(nil) @@ -331,7 +345,7 @@ var decodeTests = []decodeTest{ {input: "C109", ptr: new(*[]uint), value: &[]uint{9}}, {input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}}, - // check that input position is advanced also empty values. + // check that input position is advanced also for empty values. {input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}}, // pointer should be reset to nil diff --git a/rlp/encode.go b/rlp/encode.go index 7ac74d8fb..289bc4eaa 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -70,7 +70,7 @@ func (e flatenc) EncodeRLP(out io.Writer) error { newhead := eb.lheads[prevnheads] copy(eb.lheads[prevnheads:], eb.lheads[prevnheads+1:]) eb.lheads = eb.lheads[:len(eb.lheads)-1] - eb.lhsize -= newhead.tagsize() + eb.lhsize -= headsize(uint64(newhead.size)) return nil } @@ -155,21 +155,29 @@ type listhead struct { // encode writes head to the given buffer, which must be at least // 9 bytes long. It returns the encoded bytes. func (head *listhead) encode(buf []byte) []byte { - if head.size < 56 { - buf[0] = 0xC0 + byte(head.size) - return buf[:1] - } else { - sizesize := putint(buf[1:], uint64(head.size)) - buf[0] = 0xF7 + byte(sizesize) - return buf[:sizesize+1] - } + return buf[:puthead(buf, 0xC0, 0xF7, uint64(head.size))] } -func (head *listhead) tagsize() int { - if head.size < 56 { +// headsize returns the size of a list or string header +// for a value of the given size. +func headsize(size uint64) int { + if size < 56 { return 1 } - return 1 + intsize(uint64(head.size)) + return 1 + intsize(size) +} + +// puthead writes a list or string header to buf. +// buf must be at least 9 bytes long. +func puthead(buf []byte, smalltag, largetag byte, size uint64) int { + if size < 56 { + buf[0] = smalltag + byte(size) + return 1 + } else { + sizesize := putint(buf[1:], size) + buf[0] = largetag + byte(sizesize) + return sizesize + 1 + } } func newencbuf() *encbuf { From 483d43a15af11a9c456e4d9df0520441b947cd35 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 21 Mar 2015 00:49:58 +0100 Subject: [PATCH 72/78] whisper: use package rlp --- whisper/envelope.go | 42 ++++++++++++++++-------------------------- whisper/peer.go | 21 +++++++++------------ 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/whisper/envelope.go b/whisper/envelope.go index 9ec9fc318..15a974a2c 100644 --- a/whisper/envelope.go +++ b/whisper/envelope.go @@ -28,9 +28,9 @@ type Envelope struct { func (self *Envelope) Hash() Hash { if self.hash == EmptyHash { - self.hash = H(crypto.Sha3(common.Encode(self))) + enc, _ := rlp.EncodeToBytes(self) + self.hash = H(crypto.Sha3(enc)) } - return self.hash } @@ -76,7 +76,8 @@ func (self *Envelope) Open(prv *ecdsa.PrivateKey) (msg *Message, err error) { func (self *Envelope) proveWork(dura time.Duration) { var bestBit int d := make([]byte, 64) - copy(d[:32], common.Encode(self.withoutNonce())) + enc, _ := rlp.EncodeToBytes(self.withoutNonce()) + copy(d[:32], enc) then := time.Now().Add(dura).UnixNano() for n := uint32(0); time.Now().UnixNano() < then; { @@ -96,39 +97,28 @@ func (self *Envelope) proveWork(dura time.Duration) { func (self *Envelope) valid() bool { d := make([]byte, 64) - copy(d[:32], common.Encode(self.withoutNonce())) + enc, _ := rlp.EncodeToBytes(self.withoutNonce()) + copy(d[:32], enc) binary.BigEndian.PutUint32(d[60:], self.Nonce) return common.FirstBitSet(common.BigD(crypto.Sha3(d))) > 0 } func (self *Envelope) withoutNonce() interface{} { - return []interface{}{self.Expiry, self.Ttl, common.ByteSliceToInterface(self.Topics), self.Data} + return []interface{}{self.Expiry, self.Ttl, self.Topics, self.Data} } -func (self *Envelope) RlpData() interface{} { - return []interface{}{self.Expiry, self.Ttl, common.ByteSliceToInterface(self.Topics), self.Data, self.Nonce} -} +// rlpenv is an Envelope but is not an rlp.Decoder. +// It is used for decoding because we need to +type rlpenv Envelope func (self *Envelope) DecodeRLP(s *rlp.Stream) error { - var extenv struct { - Expiry uint32 - Ttl uint32 - Topics [][]byte - Data []byte - Nonce uint32 - } - if err := s.Decode(&extenv); err != nil { + raw, err := s.Raw() + if err != nil { return err } - - self.Expiry = extenv.Expiry - self.Ttl = extenv.Ttl - self.Topics = extenv.Topics - self.Data = extenv.Data - self.Nonce = extenv.Nonce - - // TODO We should use the stream directly here. - self.hash = H(crypto.Sha3(common.Encode(self))) - + if err := rlp.DecodeBytes(raw, (*rlpenv)(self)); err != nil { + return err + } + self.hash = H(crypto.Sha3(raw)) return nil } diff --git a/whisper/peer.go b/whisper/peer.go index ee5bffd0b..338166c25 100644 --- a/whisper/peer.go +++ b/whisper/peer.go @@ -10,7 +10,7 @@ import ( ) const ( - protocolVersion = 0x02 + protocolVersion uint64 = 0x02 ) type peer struct { @@ -66,21 +66,18 @@ out: } func (self *peer) broadcast(envelopes []*Envelope) error { - envs := make([]interface{}, len(envelopes)) - i := 0 - for _, envelope := range envelopes { - if !self.known.Has(envelope.Hash()) { - envs[i] = envelope - self.known.Add(envelope.Hash()) - i++ + envs := make([]*Envelope, 0, len(envelopes)) + for _, env := range envelopes { + if !self.known.Has(env.Hash()) { + envs = append(envs, env) + self.known.Add(env.Hash()) } } - - if i > 0 { - if err := p2p.Send(self.ws, envelopesMsg, envs[:i]); err != nil { + if len(envs) > 0 { + if err := p2p.Send(self.ws, envelopesMsg, envs); err != nil { return err } - self.peer.DebugDetailln("broadcasted", i, "message(s)") + self.peer.DebugDetailln("broadcasted", len(envs), "message(s)") } return nil } From 7c4ff3abb4693bf93b2b348f572f14f2cfcf9142 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 21 Mar 2015 00:50:20 +0100 Subject: [PATCH 73/78] eth: enable whisper again --- eth/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index b086d6a56..141c6c605 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -206,7 +206,7 @@ func New(config *Config) (*Ethereum, error) { ethProto := EthProtocol(config.ProtocolVersion, config.NetworkId, eth.txPool, eth.chainManager, eth.blockPool) protocols := []p2p.Protocol{ethProto} if config.Shh { - //protocols = append(protocols, eth.whisper.Protocol()) + protocols = append(protocols, eth.whisper.Protocol()) } eth.net = &p2p.Server{ From 069c87b960c48864dc4f1b9086adf582e1dc88a9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 21 Mar 2015 00:57:18 +0100 Subject: [PATCH 74/78] whisper: use common.Hash --- whisper/envelope.go | 23 ++++++++++++++--------- whisper/sort.go | 8 ++++++-- whisper/sort_test.go | 16 ++++++++++------ whisper/whisper.go | 28 ++++------------------------ 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/whisper/envelope.go b/whisper/envelope.go index 15a974a2c..20e3e6d39 100644 --- a/whisper/envelope.go +++ b/whisper/envelope.go @@ -18,26 +18,31 @@ const ( type Envelope struct { Expiry uint32 // Whisper protocol specifies int32, really should be int64 - Ttl uint32 // ^^^^^^ + TTL uint32 // ^^^^^^ Topics [][]byte Data []byte Nonce uint32 - hash Hash + hash common.Hash } -func (self *Envelope) Hash() Hash { - if self.hash == EmptyHash { +func (self *Envelope) Hash() common.Hash { + if (self.hash == common.Hash{}) { enc, _ := rlp.EncodeToBytes(self) - self.hash = H(crypto.Sha3(enc)) + self.hash = crypto.Sha3Hash(enc) } return self.hash } func NewEnvelope(ttl time.Duration, topics [][]byte, data *Message) *Envelope { exp := time.Now().Add(ttl) - - return &Envelope{uint32(exp.Unix()), uint32(ttl.Seconds()), topics, data.Bytes(), 0, Hash{}} + return &Envelope{ + Expiry: uint32(exp.Unix()), + TTL: uint32(ttl.Seconds()), + Topics: topics, + Data: data.Bytes(), + Nonce: 0, + } } func (self *Envelope) Seal(pow time.Duration) { @@ -104,7 +109,7 @@ func (self *Envelope) valid() bool { } func (self *Envelope) withoutNonce() interface{} { - return []interface{}{self.Expiry, self.Ttl, self.Topics, self.Data} + return []interface{}{self.Expiry, self.TTL, self.Topics, self.Data} } // rlpenv is an Envelope but is not an rlp.Decoder. @@ -119,6 +124,6 @@ func (self *Envelope) DecodeRLP(s *rlp.Stream) error { if err := rlp.DecodeBytes(raw, (*rlpenv)(self)); err != nil { return err } - self.hash = H(crypto.Sha3(raw)) + self.hash = crypto.Sha3Hash(raw) return nil } diff --git a/whisper/sort.go b/whisper/sort.go index 8c5b46e9e..313ba5ac0 100644 --- a/whisper/sort.go +++ b/whisper/sort.go @@ -1,6 +1,10 @@ package whisper -import "sort" +import ( + "sort" + + "github.com/ethereum/go-ethereum/common" +) type sortedKeys struct { k []int32 @@ -10,7 +14,7 @@ func (self *sortedKeys) Len() int { return len(self.k) } func (self *sortedKeys) Less(i, j int) bool { return self.k[i] < self.k[j] } func (self *sortedKeys) Swap(i, j int) { self.k[i], self.k[j] = self.k[j], self.k[i] } -func sortKeys(m map[int32]Hash) []int32 { +func sortKeys(m map[int32]common.Hash) []int32 { sorted := new(sortedKeys) sorted.k = make([]int32, len(m)) i := 0 diff --git a/whisper/sort_test.go b/whisper/sort_test.go index 5d8177d41..a61fde4c2 100644 --- a/whisper/sort_test.go +++ b/whisper/sort_test.go @@ -1,13 +1,17 @@ package whisper -import "testing" +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) func TestSorting(t *testing.T) { - m := map[int32]Hash{ - 1: HS("1"), - 3: HS("3"), - 2: HS("2"), - 5: HS("5"), + m := map[int32]common.Hash{ + 1: {1}, + 3: {3}, + 2: {2}, + 5: {5}, } exp := []int32{1, 2, 3, 5} res := sortKeys(m) diff --git a/whisper/whisper.go b/whisper/whisper.go index 908df973c..dbd4fc85f 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -1,12 +1,12 @@ package whisper import ( - "bytes" "crypto/ecdsa" "errors" "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/event/filter" @@ -15,26 +15,6 @@ import ( "gopkg.in/fatih/set.v0" ) -// MOVE ME -type Hash struct { - hash string -} - -var EmptyHash Hash - -func H(hash []byte) Hash { - return Hash{string(hash)} -} -func HS(hash string) Hash { - return Hash{hash} -} - -func (self Hash) Compare(other Hash) int { - return bytes.Compare([]byte(self.hash), []byte(other.hash)) -} - -// MOVE ME END - const ( statusMsg = 0x0 envelopesMsg = 0x01 @@ -55,7 +35,7 @@ type Whisper struct { filters *filter.Filters mmu sync.RWMutex - messages map[Hash]*Envelope + messages map[common.Hash]*Envelope expiry map[uint32]*set.SetNonTS quit chan struct{} @@ -65,7 +45,7 @@ type Whisper struct { func New() *Whisper { whisper := &Whisper{ - messages: make(map[Hash]*Envelope), + messages: make(map[common.Hash]*Envelope), filters: filter.New(), expiry: make(map[uint32]*set.SetNonTS), quit: make(chan struct{}), @@ -239,7 +219,7 @@ func (self *Whisper) expire() { } hashSet.Each(func(v interface{}) bool { - delete(self.messages, v.(Hash)) + delete(self.messages, v.(common.Hash)) return true }) self.expiry[then].Clear() From c28116cb3b485f01aba852fdc9559a2495db6654 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Mar 2015 14:46:50 +0100 Subject: [PATCH 75/78] Fixed incorrect recipient derived --- core/types/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 391fb46f5..7aef5ce94 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -80,7 +80,7 @@ func (self *Transaction) From() (common.Address, error) { return common.Address{}, errors.New("invalid public key") } var addr common.Address - copy(addr[:], crypto.Sha3(pubkey[1:])) + copy(addr[:], crypto.Sha3(pubkey[1:])[12:]) return addr, nil } From 4300f2a0fae793ff73ea861dfe3f90ce97f5af40 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Mar 2015 14:47:50 +0100 Subject: [PATCH 76/78] Fixed state tests --- state/state_test.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/state/state_test.go b/state/state_test.go index b6e22f891..a3d3973de 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -1,7 +1,6 @@ package state import ( - "fmt" "math/big" "testing" @@ -61,23 +60,21 @@ func (s *StateSuite) TestDump(c *checker.C) { func (s *StateSuite) SetUpTest(c *checker.C) { db, _ := ethdb.NewMemDatabase() - s.state = New(nil, db) + s.state = New(common.Hash{}, db) } func TestNull(t *testing.T) { db, _ := ethdb.NewMemDatabase() - state := New(nil, db) + state := New(common.Hash{}, db) - address := common.FromHex("0x823140710bf13990e4500136726d8b55") + address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") state.NewStateObject(address) //value := common.FromHex("0x823140710bf13990e4500136726d8b55") value := make([]byte, 16) - fmt.Println("test it here", common.NewValue(value)) - state.SetState(address, []byte{0}, value) + state.SetState(address, common.Hash{}, value) state.Update(nil) state.Sync() - value = state.GetState(address, []byte{0}) - fmt.Printf("res: %x\n", value) + value = state.GetState(address, common.Hash{}) } func (s *StateSuite) TestSnapshot(c *checker.C) { From ce862ee7589a0780cebc8a7bb1cf6a75193d55a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Mar 2015 14:51:45 +0100 Subject: [PATCH 77/78] Removed some comments --- miner/worker.go | 3 ++- xeth/xeth.go | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index ae6782aca..4a52a40fe 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -211,7 +211,8 @@ gasLimit: from, _ := tx.From() self.chain.TxState().RemoveNonce(from, tx.Nonce()) remove = append(remove, tx) - minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash().Bytes()[:4]) + minerlogger.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err) + minerlogger.Infoln(tx) case state.IsGasLimitErr(err): minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i) // Break on gas limit diff --git a/xeth/xeth.go b/xeth/xeth.go index 2c324be26..9f183aa61 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -611,7 +611,7 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt } state := self.chainManager.TxState() - nonce := state.NewNonce(from) //state.GetNonce(from) + nonce := state.NewNonce(from) tx.SetNonce(nonce) if err := self.sign(tx, from, false); err != nil { @@ -620,7 +620,6 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt if err := self.eth.TxPool().Add(tx); err != nil { return "", err } - //state.IncrementNonce(from) if contractCreation { addr := core.AddressFromMessage(tx) From fcacfabe1959c4aff6a63cb4e275f65328660601 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Mar 2015 15:09:03 +0100 Subject: [PATCH 78/78] Added new ethereum.js --- jsre/ethereum_js.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsre/ethereum_js.go b/jsre/ethereum_js.go index 8b2f6e9dd..bf194a9ac 100644 --- a/jsre/ethereum_js.go +++ b/jsre/ethereum_js.go @@ -1,3 +1,3 @@ package jsre -const Ethereum_JS = `require=function t(e,n,r){function o(i,u){if(!n[i]){if(!e[i]){var s="function"==typeof require&&require;if(!u&&s)return s(i,!0);if(a)return a(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[i]={exports:{}};e[i][0].call(l.exports,function(t){var n=e[i][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[i].exports}for(var a="function"==typeof require&&require,i=0;iy;y++)g.push(d(e.slice(0,s))),e=e.slice(s);n.push(g)}else o.prefixedType("string")(t[c].type)?(l=l.slice(s),n.push(d(e.slice(0,s))),e=e.slice(s)):(n.push(d(e.slice(0,s))),e=e.slice(s))}),n},d=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),o=n.extractTypeName(t.name),a=function(){var e=Array.prototype.slice.call(arguments);return l(t.inputs,e)};void 0===e[r]&&(e[r]=a),e[r][o]=a}),e},h=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),o=n.extractTypeName(t.name),a=function(e){return m(t.outputs,e)};void 0===e[r]&&(e[r]=a),e[r][o]=a}),e};e.exports={inputParser:d,outputParser:h,formatInput:l,formatOutput:m}},{"../utils/config":4,"../utils/utils":5,"./formatters":2,"./types":3}],2:[function(t,e){var n=t("../utils/utils"),r=t("../utils/config"),o=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t){var e=2*r.ETH_PADDING;return BigNumber.config(r.ETH_BIGNUMBER_ROUNDING_MODE),o(n.toTwosComplement(t).round().toString(16),e)},i=function(t){return n.fromAscii(t,r.ETH_PADDING).substr(2)},u=function(t){return"000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0")},s=function(t){return a(new BigNumber(t).times(new BigNumber(2).pow(128)))},c=function(t){return"1"===new BigNumber(t.substr(0,1),16).toString(2).substr(0,1)},l=function(t){return t=t||"0",c(t)?new BigNumber(t,16).minus(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new BigNumber(t,16)},f=function(t){return t=t||"0",new BigNumber(t,16)},p=function(t){return l(t).dividedBy(new BigNumber(2).pow(128))},m=function(t){return f(t).dividedBy(new BigNumber(2).pow(128))},d=function(t){return"0x"+t},h=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t?!0:!1},g=function(t){return n.toAscii(t)},y=function(t){return"0x"+t.slice(t.length-40,t.length)};e.exports={formatInputInt:a,formatInputString:i,formatInputBool:u,formatInputReal:s,formatOutputInt:l,formatOutputUInt:f,formatOutputReal:p,formatOutputUReal:m,formatOutputHash:d,formatOutputBool:h,formatOutputString:g,formatOutputAddress:y}},{"../utils/config":4,"../utils/utils":5}],3:[function(t,e){var n=t("./formatters"),r=function(t){return function(e){return 0===e.indexOf(t)}},o=function(t){return function(e){return t===e}},a=function(){return[{type:r("uint"),format:n.formatInputInt},{type:r("int"),format:n.formatInputInt},{type:r("hash"),format:n.formatInputInt},{type:r("string"),format:n.formatInputString},{type:r("real"),format:n.formatInputReal},{type:r("ureal"),format:n.formatInputReal},{type:o("address"),format:n.formatInputInt},{type:o("bool"),format:n.formatInputBool}]},i=function(){return[{type:r("uint"),format:n.formatOutputUInt},{type:r("int"),format:n.formatOutputInt},{type:r("hash"),format:n.formatOutputHash},{type:r("string"),format:n.formatOutputString},{type:r("real"),format:n.formatOutputReal},{type:r("ureal"),format:n.formatOutputUReal},{type:o("address"),format:n.formatOutputAddress},{type:o("bool"),format:n.formatOutputBool}]};e.exports={prefixedType:r,namedType:o,inputTypes:a,outputTypes:i}},{"./formatters":2}],4:[function(t,e){var n=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:n,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,ETH_DEFAULTBLOCK:"latest"}},{}],5:[function(t,e){var n={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},r=function(t,e){for(var n=!1,r=0;rn;n+=2){var o=parseInt(t.substr(n,2),16);if(0===o)break;e+=String.fromCharCode(o)}return e},a=function(t){for(var e="",n=0;n1?(t[n[0]]||(t[n[0]]={}),t[n[0]][n[1]]=r):t[n[0]]=r})},d=function(t,e){e.forEach(function(e){var n={};n.get=function(){return e.newProperty&&console.warn("This property is deprecated please use web3."+e.newProperty+" instead."),v.manager.send({method:e.getter,outputFormatter:e.outputFormatter})},e.setter&&(n.set=function(t){return e.newProperty&&console.warn("This property is deprecated please use web3."+e.newProperty+" instead."),v.manager.send({method:e.setter,params:[t],inputFormatter:e.inputFormatter})}),n.enumerable=!e.newProperty,Object.defineProperty(t,e.name,n)})},h=function(t,e,n,r){v.manager.startPolling({method:t,params:[e]},e,n,r)},g=function(t){v.manager.stopPolling(t)},y={startPolling:h.bind(null,"eth_getFilterChanges"),stopPolling:g},b={startPolling:h.bind(null,"shh_getFilterChanges"),stopPolling:g},v={manager:l(),providers:{},setProvider:function(t){v.manager.setProvider(t)},reset:function(){v.manager.reset()},toHex:s.toHex,toAscii:s.toAscii,fromAscii:s.fromAscii,toDecimal:s.toDecimal,fromDecimal:s.fromDecimal,toBigNumber:s.toBigNumber,toWei:s.toWei,fromWei:s.fromWei,isAddress:s.isAddress,net:{},eth:{contractFromAbi:function(t){return console.warn("Initiating a contract like this is deprecated please use var MyContract = eth.contract(abi); new MyContract(address); instead."),function(e){e=e||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var n=v.eth.contract(e,t);return n.address=e,n}},filter:function(t,e,n){return t._isEvent?t(e,n):u(t,y,c.outputLogFormatter)},watch:function(t,e,n){return console.warn("eth.watch() is deprecated please use eth.filter() instead."),this.filter(t,e,n)}},db:{},shh:{filter:function(t){return u(t,b,c.outputPostFormatter)},watch:function(t){return console.warn("shh.watch() is deprecated please use shh.filter() instead."),this.filter(t)}}};Object.defineProperty(v.eth,"defaultBlock",{get:function(){return f.ETH_DEFAULTBLOCK},set:function(t){return f.ETH_DEFAULTBLOCK=t,f.ETH_DEFAULTBLOCK}}),m(v,p()),m(v.net,n.methods),d(v.net,n.properties),m(v.eth,r.methods),d(v.eth,r.properties),m(v.db,o.methods()),m(v.shh,a.methods()),m(y,i.eth()),m(b,i.shh()),e.exports=v},{"./solidity/formatters":2,"./utils/config":4,"./utils/utils":5,"./web3/db":8,"./web3/eth":9,"./web3/filter":11,"./web3/net":15,"./web3/requestmanager":17,"./web3/shh":18,"./web3/watches":20}],7:[function(t,e){function n(t,e){t.forEach(function(t){if(-1===t.name.indexOf("(")){var e=t.name,n=t.inputs.map(function(t){return t.type}).join();t.name=e+"("+n+")"}});var n={};return c(n),l(n,t,e),f(n,t,e),p(n,t,e),n}var r=t("../web3"),o=t("../solidity/abi"),a=t("../utils/utils"),i=t("./event"),u=t("./signature"),s=function(t){r._currentContractAbi=t.abi,r._currentContractAddress=t.address,r._currentContractMethodName=t.method,r._currentContractMethodParams=t.params},c=function(t){t.call=function(e){return t._isTransaction=!1,t._options=e,t},t.sendTransaction=function(e){return t._isTransaction=!0,t._options=e,t},t.transact=function(e){return console.warn("myContract.transact() is deprecated please use myContract.sendTransaction() instead."),t.sendTransaction(e)},t._options={},["gas","gasPrice","value","from"].forEach(function(e){t[e]=function(n){return t._options[e]=n,t}})},l=function(t,e,n){var i=o.inputParser(e),c=o.outputParser(e);a.filterFunctions(e).forEach(function(o){var l=a.extractDisplayName(o.name),f=a.extractTypeName(o.name),p=function(){var a=Array.prototype.slice.call(arguments),p=u.functionSignatureFromAscii(o.name),m=i[l][f].apply(null,a),d=t._options||{};d.to=n,d.data=p+m;var h=t._isTransaction===!0||t._isTransaction!==!1&&!o.constant,g=d.collapse!==!1;if(t._options={},t._isTransaction=null,h)return s({abi:e,address:n,method:o.name,params:a}),void r.eth.sendTransaction(d);var y=r.eth.call(d),b=c[l][f](y);return g&&(1===b.length?b=b[0]:0===b.length&&(b=null)),b};void 0===t[l]&&(t[l]=p),t[l][f]=p})},f=function(t,e,n){t.address=n,t._onWatchEventResult=function(t){var n=event.getMatchingEvent(a.filterEvents(e)),r=i.outputParser(n);return r(t)},Object.defineProperty(t,"topics",{get:function(){return a.filterEvents(e).map(function(t){return u.eventSignatureFromAscii(t.name)})}})},p=function(t,e,n){a.filterEvents(e).forEach(function(e){var o=function(){var t=Array.prototype.slice.call(arguments),o=u.eventSignatureFromAscii(e.name),a=i.inputParser(n,o,e),s=a.apply(null,t),c=function(t){var n=i.outputParser(e);return n(t)};return r.eth.filter(s,void 0,void 0,c)};o._isEvent=!0;var s=a.extractDisplayName(e.name),c=a.extractTypeName(e.name);void 0===t[s]&&(t[s]=o),t[s][c]=o})},m=function(t){return t instanceof Array&&1===arguments.length?n.bind(null,t):(console.warn("Initiating a contract like this is deprecated please use var MyContract = eth.contract(abi); new MyContract(address); instead."),new n(arguments[1],arguments[0]))};e.exports=m},{"../solidity/abi":1,"../utils/utils":5,"../web3":6,"./event":10,"./signature":19}],8:[function(t,e){var n=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};e.exports={methods:n}},{}],9:[function(t,e){var n=t("./formatters"),r=t("../utils/utils"),o=function(t){return r.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getBlockByHash":"eth_getBlockByNumber"},a=function(t){return r.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getTransactionByBlockHashAndIndex":"eth_getTransactionByBlockNumberAndIndex"},i=function(t){return r.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getUncleByBlockHashAndIndex":"eth_getUncleByBlockNumberAndIndex"},u=function(t){return r.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getBlockTransactionCountByHash":"eth_getBlockTransactionCountByNumber"},s=function(t){return r.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getUncleCountByBlockHash":"eth_getUncleCountByBlockNumber"},c=[{name:"getBalance",call:"eth_getBalance",addDefaultblock:2,outputFormatter:n.convertToBigNumber},{name:"getStorage",call:"eth_getStorage",addDefaultblock:2},{name:"getStorageAt",call:"eth_getStorageAt",addDefaultblock:3,inputFormatter:r.toHex},{name:"getData",call:"eth_getData",addDefaultblock:2},{name:"getBlock",call:o,outputFormatter:n.outputBlockFormatter,inputFormatter:[r.toHex,function(t){return t?!0:!1}]},{name:"getUncle",call:i,outputFormatter:n.outputBlockFormatter,inputFormatter:[r.toHex,r.toHex,function(t){return t?!0:!1}]},{name:"getCompilers",call:"eth_getCompilers"},{name:"getBlockTransactionCount",call:u,outputFormatter:r.toDecimal,inputFormatter:r.toHex},{name:"getBlockUncleCount",call:s,outputFormatter:r.toDecimal,inputFormatter:r.toHex},{name:"getTransaction",call:"eth_getTransactionByHash",outputFormatter:n.outputTransactionFormatter},{name:"getTransactionFromBlock",call:a,outputFormatter:n.outputTransactionFormatter,inputFormatter:r.toHex},{name:"getTransactionCount",call:"eth_getTransactionCount",addDefaultblock:2,outputFormatter:r.toDecimal},{name:"sendTransaction",call:"eth_sendTransaction",inputFormatter:n.inputTransactionFormatter},{name:"call",call:"eth_call",addDefaultblock:2,inputFormatter:n.inputCallFormatter},{name:"compile.solidity",call:"eth_compileSolidity",inputFormatter:r.toHex},{name:"compile.lll",call:"eth_compileLLL",inputFormatter:r.toHex},{name:"compile.serpent",call:"eth_compileSerpent",inputFormatter:r.toHex},{name:"flush",call:"eth_flush"},{name:"balanceAt",call:"eth_balanceAt",newMethod:"eth.getBalance"},{name:"stateAt",call:"eth_stateAt",newMethod:"eth.getStorageAt"},{name:"storageAt",call:"eth_storageAt",newMethod:"eth.getStorage"},{name:"countAt",call:"eth_countAt",newMethod:"eth.getTransactionCount"},{name:"codeAt",call:"eth_codeAt",newMethod:"eth.getData"},{name:"transact",call:"eth_transact",newMethod:"eth.sendTransaction"},{name:"block",call:o,newMethod:"eth.getBlock"},{name:"transaction",call:a,newMethod:"eth.getTransaction"},{name:"uncle",call:i,newMethod:"eth.getUncle"},{name:"compilers",call:"eth_compilers",newMethod:"eth.getCompilers"},{name:"solidity",call:"eth_solidity",newMethod:"eth.compile.solidity"},{name:"lll",call:"eth_lll",newMethod:"eth.compile.lll"},{name:"serpent",call:"eth_serpent",newMethod:"eth.compile.serpent"},{name:"transactionCount",call:u,newMethod:"eth.getBlockTransactionCount"},{name:"uncleCount",call:s,newMethod:"eth.getBlockUncleCount"},{name:"logs",call:"eth_logs"}],l=[{name:"coinbase",getter:"eth_coinbase"},{name:"mining",getter:"eth_mining"},{name:"gasPrice",getter:"eth_gasPrice",outputFormatter:n.convertToBigNumber},{name:"accounts",getter:"eth_accounts"},{name:"blockNumber",getter:"eth_blockNumber",outputFormatter:r.toDecimal},{name:"listening",getter:"net_listening",setter:"eth_setListening",newProperty:"net.listening"},{name:"peerCount",getter:"net_peerCount",newProperty:"net.peerCount"},{name:"number",getter:"eth_number",newProperty:"eth.blockNumber"}];e.exports={methods:c,properties:l}},{"../utils/utils":5,"./formatters":12}],10:[function(t,e){var n=t("../solidity/abi"),r=t("../utils/utils"),o=t("./signature"),a=function(t,e){return t.filter(function(t){return t.indexed===e})},i=function(t,e){var n=r.findIndex(t,function(t){return t.name===e});return-1===n?void console.error("indexed param with name "+e+" not found"):t[n]},u=function(t,e){return Object.keys(e).map(function(r){var o=[i(a(t.inputs,!0),r)],u=e[r];return u instanceof Array?u.map(function(t){return n.formatInput(o,[t])}):n.formatInput(o,[u])})},s=function(t,e,n){return function(r,o){var a=o||{};return a.address=t,a.topics=[],a.topics.push(e),r&&(a.topics=a.topics.concat(u(n,r))),a}},c=function(t,e,n){var r=e.slice(),o=n.slice();return t.reduce(function(t,e){var n;return n=e.indexed?r.splice(0,1)[0]:o.splice(0,1)[0],t[e.name]=n,t},{})},l=function(t){return function(e){var o={event:r.extractDisplayName(t.name),number:e.number,hash:e.hash,args:{}};if(e.topics=e.topic,!e.topics)return o;var i=a(t.inputs,!0),u="0x"+e.topics.slice(1,e.topics.length).map(function(t){return t.slice(2)}).join(""),s=n.formatOutput(i,u),l=a(t.inputs,!1),f=n.formatOutput(l,e.data);return o.args=c(t.inputs,s,f),o}},f=function(t,e){for(var n=0;nv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]);`