diff --git a/block_pool.go b/block_pool.go index 38827242d0..0a668e111a 100644 --- a/block_pool.go +++ b/block_pool.go @@ -52,59 +52,34 @@ func (self *BlockPool) AddHash(hash []byte) { func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { hash := string(b.Hash()) - if self.pool[hash] == nil { + if self.pool[hash] == nil && !self.eth.BlockChain().HasBlock(b.Hash()) { self.hashPool = append(self.hashPool, b.Hash()) - self.pool[hash] = &block{peer, nil} + self.pool[hash] = &block{peer, b} + } else if self.pool[hash] != nil { + self.pool[hash].block = b } - - self.pool[hash].block = b } -func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool { - self.mut.Lock() - defer self.mut.Unlock() - - if self.IsLinked() { - for i, hash := range self.hashPool { - if self.pool[string(hash)] == nil { - continue - } +func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) { - block := self.pool[string(hash)].block - if block != nil { - f(block) - - delete(self.pool, string(hash)) - } else { - self.hashPool = self.hashPool[i:] - - return false - } + var blocks ethchain.Blocks + for _, item := range self.pool { + if item.block != nil { + blocks = append(blocks, item.block) } - - return true } - return false -} - -func (self *BlockPool) IsLinked() bool { - if len(self.hashPool) == 0 { - return false - } + ethchain.BlockBy(ethchain.Number).Sort(blocks) + for _, block := range blocks { + if self.eth.BlockChain().HasBlock(block.PrevHash) { + f(block) - for i := 0; i < len(self.hashPool); i++ { - item := self.pool[string(self.hashPool[i])] - if item != nil && item.block != nil { - if self.eth.BlockChain().HasBlock(item.block.PrevHash) { - self.hashPool = self.hashPool[i:] - - return true - } + hash := block.Hash() + self.hashPool = ethutil.DeleteFromByteSlice(self.hashPool, hash) + delete(self.pool, string(hash)) } - } - return false + } } func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) { diff --git a/ethchain/block.go b/ethchain/block.go index fde6ff04a3..157be2a529 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "math/big" + "sort" _ "strconv" "time" @@ -42,9 +43,32 @@ func (self Blocks) AsSet() ethutil.UniqueSet { return set } +type BlockBy func(b1, b2 *Block) bool + +func (self BlockBy) Sort(blocks Blocks) { + bs := blockSorter{ + blocks: blocks, + by: self, + } + sort.Sort(bs) +} + +type blockSorter struct { + blocks Blocks + by func(b1, b2 *Block) bool +} + +func (self blockSorter) Len() int { return len(self.blocks) } +func (self blockSorter) Swap(i, j int) { + self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] +} +func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } + +func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } + type Block struct { // Hash to the previous block - PrevHash []byte + PrevHash ethutil.Bytes // Uncles of this block Uncles Blocks UncleSha []byte @@ -68,7 +92,7 @@ type Block struct { // Extra data Extra string // Block Nonce for verification - Nonce []byte + Nonce ethutil.Bytes // List of transactions and/or contracts transactions []*Transaction receipts []*Receipt @@ -117,8 +141,9 @@ func CreateBlock(root interface{}, } // Returns a hash of the block -func (block *Block) Hash() []byte { - return ethcrypto.Sha3Bin(block.Value().Encode()) +func (block *Block) Hash() ethutil.Bytes { + return ethcrypto.Sha3Bin(ethutil.NewValue(block.header()).Encode()) + //return ethcrypto.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2d88a0f534..5d0d652df1 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -58,24 +58,20 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { block.MinGasPrice = big.NewInt(10000000000000) - if bc.CurrentBlock != nil { - var mul *big.Int - if block.Time < lastBlockTime+5 { - mul = big.NewInt(1) + parent := bc.CurrentBlock + if parent != nil { + diff := new(big.Int) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= lastBlockTime+5 { + diff.Sub(parent.Difficulty, adjust) } else { - mul = big.NewInt(-1) + diff.Add(parent.Difficulty, adjust) } - - diff := new(big.Int) - diff.Add(diff, bc.CurrentBlock.Difficulty) - diff.Div(diff, big.NewInt(1024)) - diff.Mul(diff, mul) - diff.Add(diff, bc.CurrentBlock.Difficulty) block.Difficulty = diff - block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) + } return block @@ -159,6 +155,9 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() + if bc.LastBlockNumber == 0 { + bc.genesisBlock = block + } } else { AddTestNetFunds(bc.genesisBlock) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a165ed79d7..1ccaa560f9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -217,13 +217,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - // I'm not sure, but I don't know if there should be thrown - // any errors at this time. if err = sm.AccumelateRewards(state, block, parent); err != nil { statelogger.Errorln("Error accumulating reward", err) return err } + state.Update() + if !block.State().Cmp(state) { err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) return @@ -335,7 +335,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { } func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { - reward := new(big.Int) + reward := new(big.Int).Set(BlockReward) knownUncles := ethutil.Set(parent.Uncles) nonces := ethutil.NewSet(block.Nonce) @@ -358,6 +358,8 @@ func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent * return UncleError("Uncle in chain") } + nonces.Insert(uncle.Nonce) + r := new(big.Int) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) diff --git a/ethstate/dump.go b/ethstate/dump.go index be60a05fcf..cdd4228b89 100644 --- a/ethstate/dump.go +++ b/ethstate/dump.go @@ -28,7 +28,7 @@ func (self *State) Dump() []byte { self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) { stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes()) - account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.CodeHash)} + account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)} account.Storage = make(map[string]string) stateObject.EachStorage(func(key string, value *ethutil.Value) { diff --git a/ethstate/state.go b/ethstate/state.go index 42bbf021ba..0e87659fc7 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -3,7 +3,6 @@ package ethstate import ( "math/big" - "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -66,7 +65,9 @@ func (self *State) GetCode(addr []byte) []byte { func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() - ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code) + if len(stateObject.CodeHash()) > 0 { + ethutil.Config.Db.Put(stateObject.CodeHash(), stateObject.Code) + } self.Trie.Update(string(addr), string(stateObject.RlpEncode())) } diff --git a/ethstate/state_object.go b/ethstate/state_object.go index 6fc0696a84..be083e80af 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -32,7 +32,7 @@ type StateObject struct { address []byte // Shared attributes Balance *big.Int - CodeHash []byte + codeHash []byte Nonce uint64 // Contract related attributes State *State @@ -236,7 +236,7 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { func (self *StateObject) Copy() *StateObject { stateObject := NewStateObject(self.Address()) stateObject.Balance.Set(self.Balance) - stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash) + stateObject.codeHash = ethutil.CopyBytes(self.codeHash) stateObject.Nonce = self.Nonce if self.State != nil { stateObject.State = self.State.Copy() @@ -297,12 +297,17 @@ func (c *StateObject) RlpEncode() []byte { } else { root = "" } + + return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, c.CodeHash()}) +} + +func (c *StateObject) CodeHash() ethutil.Bytes { var codeHash []byte if len(c.Code) > 0 { codeHash = ethcrypto.Sha3Bin(c.Code) } - return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, codeHash}) + return codeHash } func (c *StateObject) RlpDecode(data []byte) { @@ -314,9 +319,9 @@ func (c *StateObject) RlpDecode(data []byte) { c.storage = make(map[string]*ethutil.Value) c.gasPool = new(big.Int) - c.CodeHash = decoder.Get(3).Bytes() + c.codeHash = decoder.Get(3).Bytes() - c.Code, _ = ethutil.Config.Db.Get(c.CodeHash) + c.Code, _ = ethutil.Config.Db.Get(c.codeHash) } // Storage change object. Used by the manifest for notifying changes to diff --git a/ethutil/bytes.go b/ethutil/bytes.go index e38f894540..f151d16ee7 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -9,6 +9,22 @@ import ( "strings" ) +type Bytes []byte + +func (self Bytes) String() string { + return string(self) +} + +func DeleteFromByteSlice(s [][]byte, hash []byte) [][]byte { + for i, h := range s { + if bytes.Compare(h, hash) == 0 { + return append(s[:i], s[i+1:]...) + } + } + + return s +} + // Number to bytes // // Returns the number in bytes with the specified base diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 17ff627eb5..febfb78e19 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -124,6 +124,8 @@ func Encode(object interface{}) []byte { } else { buff.Write(Encode(t.Bytes())) } + case Bytes: + buff.Write(Encode([]byte(t))) case []byte: if len(t) == 1 && t[0] <= 0x7f { buff.Write(t) diff --git a/ethutil/set.go b/ethutil/set.go index 80e2edde29..7955edac07 100644 --- a/ethutil/set.go +++ b/ethutil/set.go @@ -4,9 +4,13 @@ type Settable interface { AsSet() UniqueSet } -type UniqueSet map[interface{}]struct{} +type Stringable interface { + String() string +} + +type UniqueSet map[string]struct{} -func NewSet(v ...interface{}) UniqueSet { +func NewSet(v ...Stringable) UniqueSet { set := make(UniqueSet) for _, val := range v { set.Insert(val) @@ -15,14 +19,14 @@ func NewSet(v ...interface{}) UniqueSet { return set } -func (self UniqueSet) Insert(k interface{}) UniqueSet { - self[k] = struct{}{} +func (self UniqueSet) Insert(k Stringable) UniqueSet { + self[k.String()] = struct{}{} return self } -func (self UniqueSet) Include(k interface{}) bool { - _, ok := self[k] +func (self UniqueSet) Include(k Stringable) bool { + _, ok := self[k.String()] return ok } diff --git a/peer.go b/peer.go index 349d020978..32885aed8a 100644 --- a/peer.go +++ b/peer.go @@ -24,7 +24,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 28 + ProtocolVersion = 32 // Current P2P version P2PVersion = 0 // Interval for ping/pong message @@ -276,13 +276,15 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { return } } else { - if !p.statusKnown { - switch msg.Type { - case ethwire.MsgStatusTy: // Ok - default: // Anything but ack is allowed - return + /* + if !p.statusKnown { + switch msg.Type { + case ethwire.MsgStatusTy: // Ok + default: // Anything but ack is allowed + return + } } - } + */ } peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) @@ -488,19 +490,25 @@ func (p *Peer) HandleInbound() { it := msg.Data.NewIterator() for it.Next() { block := ethchain.NewBlockFromRlpValue(it.Value()) + //fmt.Printf("%v %x - %x\n", block.Number, block.Hash()[0:4], block.PrevHash[0:4]) blockPool.SetBlock(block, p) p.lastBlockReceived = time.Now() } - linked := blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { - p.ethereum.StateManager().Process(block, false) + blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { + err := p.ethereum.StateManager().Process(block, false) + if err != nil { + peerlogger.Infoln(err) + } }) - if !linked { - p.FetchBlocks() - } + /* + if !linked { + p.FetchBlocks() + } + */ } } } @@ -596,20 +604,6 @@ func (p *Peer) Stop() { p.ethereum.RemovePeer(p) } -/* -func (p *Peer) pushHandshake() error { - pubkey := p.ethereum.KeyManager().PublicKey() - msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:], - p.ethereum.BlockChain().TD.Uint64(), p.ethereum.BlockChain().CurrentBlock.Hash(), - }) - - p.QueueMessage(msg) - - return nil -} -*/ - func (p *Peer) peersMessage() *ethwire.Msg { outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) // Serialise each peer