Improved catching up and refactored

This commit is contained in:
obscuren 2014-09-15 15:42:12 +02:00
parent 2f614900e8
commit 33a0dec8a1
11 changed files with 129 additions and 106 deletions

@ -52,59 +52,34 @@ func (self *BlockPool) AddHash(hash []byte) {
func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) {
hash := string(b.Hash()) 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.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 { func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) {
self.mut.Lock()
defer self.mut.Unlock()
if self.IsLinked() { var blocks ethchain.Blocks
for i, hash := range self.hashPool { for _, item := range self.pool {
if self.pool[string(hash)] == nil { if item.block != nil {
continue blocks = append(blocks, item.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
}
}
return true
}
return false
}
func (self *BlockPool) IsLinked() bool {
if len(self.hashPool) == 0 {
return false
}
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
}
} }
} }
return false ethchain.BlockBy(ethchain.Number).Sort(blocks)
for _, block := range blocks {
if self.eth.BlockChain().HasBlock(block.PrevHash) {
f(block)
hash := block.Hash()
self.hashPool = ethutil.DeleteFromByteSlice(self.hashPool, hash)
delete(self.pool, string(hash))
}
}
} }
func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) { func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) {

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"math/big" "math/big"
"sort"
_ "strconv" _ "strconv"
"time" "time"
@ -42,9 +43,32 @@ func (self Blocks) AsSet() ethutil.UniqueSet {
return set 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 { type Block struct {
// Hash to the previous block // Hash to the previous block
PrevHash []byte PrevHash ethutil.Bytes
// Uncles of this block // Uncles of this block
Uncles Blocks Uncles Blocks
UncleSha []byte UncleSha []byte
@ -68,7 +92,7 @@ type Block struct {
// Extra data // Extra data
Extra string Extra string
// Block Nonce for verification // Block Nonce for verification
Nonce []byte Nonce ethutil.Bytes
// List of transactions and/or contracts // List of transactions and/or contracts
transactions []*Transaction transactions []*Transaction
receipts []*Receipt receipts []*Receipt
@ -117,8 +141,9 @@ func CreateBlock(root interface{},
} }
// Returns a hash of the block // Returns a hash of the block
func (block *Block) Hash() []byte { func (block *Block) Hash() ethutil.Bytes {
return ethcrypto.Sha3Bin(block.Value().Encode()) return ethcrypto.Sha3Bin(ethutil.NewValue(block.header()).Encode())
//return ethcrypto.Sha3Bin(block.Value().Encode())
} }
func (block *Block) HashNoNonce() []byte { func (block *Block) HashNoNonce() []byte {

@ -58,24 +58,20 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
block.MinGasPrice = big.NewInt(10000000000000) block.MinGasPrice = big.NewInt(10000000000000)
if bc.CurrentBlock != nil { parent := bc.CurrentBlock
var mul *big.Int if parent != nil {
if block.Time < lastBlockTime+5 {
mul = big.NewInt(1)
} else {
mul = big.NewInt(-1)
}
diff := new(big.Int) diff := new(big.Int)
diff.Add(diff, bc.CurrentBlock.Difficulty)
diff.Div(diff, big.NewInt(1024)) adjust := new(big.Int).Rsh(parent.Difficulty, 10)
diff.Mul(diff, mul) if block.Time >= lastBlockTime+5 {
diff.Add(diff, bc.CurrentBlock.Difficulty) diff.Sub(parent.Difficulty, adjust)
} else {
diff.Add(parent.Difficulty, adjust)
}
block.Difficulty = diff block.Difficulty = diff
block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1)
block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) block.GasLimit = block.CalcGasLimit(bc.CurrentBlock)
} }
return block return block
@ -159,6 +155,9 @@ func (bc *BlockChain) setLastBlock() {
bc.LastBlockHash = block.Hash() bc.LastBlockHash = block.Hash()
bc.LastBlockNumber = block.Number.Uint64() bc.LastBlockNumber = block.Number.Uint64()
if bc.LastBlockNumber == 0 {
bc.genesisBlock = block
}
} else { } else {
AddTestNetFunds(bc.genesisBlock) AddTestNetFunds(bc.genesisBlock)

@ -217,13 +217,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
return err 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 { if err = sm.AccumelateRewards(state, block, parent); err != nil {
statelogger.Errorln("Error accumulating reward", err) statelogger.Errorln("Error accumulating reward", err)
return err return err
} }
state.Update()
if !block.State().Cmp(state) { if !block.State().Cmp(state) {
err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root)
return return
@ -335,7 +335,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error {
} }
func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *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) knownUncles := ethutil.Set(parent.Uncles)
nonces := ethutil.NewSet(block.Nonce) nonces := ethutil.NewSet(block.Nonce)
@ -358,6 +358,8 @@ func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *
return UncleError("Uncle in chain") return UncleError("Uncle in chain")
} }
nonces.Insert(uncle.Nonce)
r := new(big.Int) r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))

@ -28,7 +28,7 @@ func (self *State) Dump() []byte {
self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) { self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) {
stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes()) 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) account.Storage = make(map[string]string)
stateObject.EachStorage(func(key string, value *ethutil.Value) { stateObject.EachStorage(func(key string, value *ethutil.Value) {

@ -3,7 +3,6 @@ package ethstate
import ( import (
"math/big" "math/big"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
@ -66,7 +65,9 @@ func (self *State) GetCode(addr []byte) []byte {
func (self *State) UpdateStateObject(stateObject *StateObject) { func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address() 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())) self.Trie.Update(string(addr), string(stateObject.RlpEncode()))
} }

@ -32,7 +32,7 @@ type StateObject struct {
address []byte address []byte
// Shared attributes // Shared attributes
Balance *big.Int Balance *big.Int
CodeHash []byte codeHash []byte
Nonce uint64 Nonce uint64
// Contract related attributes // Contract related attributes
State *State State *State
@ -236,7 +236,7 @@ func (self *StateObject) RefundGas(gas, price *big.Int) {
func (self *StateObject) Copy() *StateObject { func (self *StateObject) Copy() *StateObject {
stateObject := NewStateObject(self.Address()) stateObject := NewStateObject(self.Address())
stateObject.Balance.Set(self.Balance) stateObject.Balance.Set(self.Balance)
stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash) stateObject.codeHash = ethutil.CopyBytes(self.codeHash)
stateObject.Nonce = self.Nonce stateObject.Nonce = self.Nonce
if self.State != nil { if self.State != nil {
stateObject.State = self.State.Copy() stateObject.State = self.State.Copy()
@ -297,12 +297,17 @@ func (c *StateObject) RlpEncode() []byte {
} else { } else {
root = "" root = ""
} }
return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, c.CodeHash()})
}
func (c *StateObject) CodeHash() ethutil.Bytes {
var codeHash []byte var codeHash []byte
if len(c.Code) > 0 { if len(c.Code) > 0 {
codeHash = ethcrypto.Sha3Bin(c.Code) codeHash = ethcrypto.Sha3Bin(c.Code)
} }
return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, codeHash}) return codeHash
} }
func (c *StateObject) RlpDecode(data []byte) { func (c *StateObject) RlpDecode(data []byte) {
@ -314,9 +319,9 @@ func (c *StateObject) RlpDecode(data []byte) {
c.storage = make(map[string]*ethutil.Value) c.storage = make(map[string]*ethutil.Value)
c.gasPool = new(big.Int) 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 // Storage change object. Used by the manifest for notifying changes to

@ -9,6 +9,22 @@ import (
"strings" "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 // Number to bytes
// //
// Returns the number in bytes with the specified base // Returns the number in bytes with the specified base

@ -124,6 +124,8 @@ func Encode(object interface{}) []byte {
} else { } else {
buff.Write(Encode(t.Bytes())) buff.Write(Encode(t.Bytes()))
} }
case Bytes:
buff.Write(Encode([]byte(t)))
case []byte: case []byte:
if len(t) == 1 && t[0] <= 0x7f { if len(t) == 1 && t[0] <= 0x7f {
buff.Write(t) buff.Write(t)

@ -4,9 +4,13 @@ type Settable interface {
AsSet() UniqueSet AsSet() UniqueSet
} }
type UniqueSet map[interface{}]struct{} type Stringable interface {
String() string
}
func NewSet(v ...interface{}) UniqueSet { type UniqueSet map[string]struct{}
func NewSet(v ...Stringable) UniqueSet {
set := make(UniqueSet) set := make(UniqueSet)
for _, val := range v { for _, val := range v {
set.Insert(val) set.Insert(val)
@ -15,14 +19,14 @@ func NewSet(v ...interface{}) UniqueSet {
return set return set
} }
func (self UniqueSet) Insert(k interface{}) UniqueSet { func (self UniqueSet) Insert(k Stringable) UniqueSet {
self[k] = struct{}{} self[k.String()] = struct{}{}
return self return self
} }
func (self UniqueSet) Include(k interface{}) bool { func (self UniqueSet) Include(k Stringable) bool {
_, ok := self[k] _, ok := self[k.String()]
return ok return ok
} }

46
peer.go

@ -24,7 +24,7 @@ const (
// The size of the output buffer for writing messages // The size of the output buffer for writing messages
outputBufferSize = 50 outputBufferSize = 50
// Current protocol version // Current protocol version
ProtocolVersion = 28 ProtocolVersion = 32
// Current P2P version // Current P2P version
P2PVersion = 0 P2PVersion = 0
// Interval for ping/pong message // Interval for ping/pong message
@ -276,13 +276,15 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
return return
} }
} else { } else {
if !p.statusKnown { /*
switch msg.Type { if !p.statusKnown {
case ethwire.MsgStatusTy: // Ok switch msg.Type {
default: // Anything but ack is allowed case ethwire.MsgStatusTy: // Ok
return default: // Anything but ack is allowed
return
}
} }
} */
} }
peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) 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() it := msg.Data.NewIterator()
for it.Next() { for it.Next() {
block := ethchain.NewBlockFromRlpValue(it.Value()) 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) blockPool.SetBlock(block, p)
p.lastBlockReceived = time.Now() p.lastBlockReceived = time.Now()
} }
linked := blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { blockPool.CheckLinkAndProcess(func(block *ethchain.Block) {
p.ethereum.StateManager().Process(block, false) 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) 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 { func (p *Peer) peersMessage() *ethwire.Msg {
outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) outPeers := make([]interface{}, len(p.ethereum.InOutPeers()))
// Serialise each peer // Serialise each peer