Merge branch 'frontier/blockpool' of https://github.com/ethersphere/go-ethereum into ethersphere-frontier/blockpool

pull/700/head
obscuren 10 years ago
commit 46898f1e55
  1. 110
      blockpool/blockpool.go
  2. 4
      blockpool/blockpool_test.go
  3. 2
      blockpool/blockpool_util_test.go
  4. 45
      blockpool/errors_test.go
  5. 52
      blockpool/peers.go
  6. 12
      blockpool/peers_test.go
  7. 2
      blockpool/section.go
  8. 7
      blockpool/status_test.go
  9. 1
      core/chain_manager.go
  10. 4
      core/types/block.go

@ -132,6 +132,7 @@ type node struct {
block *types.Block block *types.Block
hashBy string hashBy string
blockBy string blockBy string
peers map[string]bool
td *big.Int td *big.Int
} }
@ -376,13 +377,14 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st
var nodes []*node var nodes []*node
hash, ok = next() hash, ok = next()
bestpeer.lock.Lock() bestpeer.lock.RLock()
plog.Debugf("AddBlockHashes: peer <%s> starting from [%s] (peer head: %s)", peerId, hex(bestpeer.parentHash), hex(bestpeer.currentBlockHash)) 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 // first check if we are building the head section of a peer's chain
if bestpeer.parentHash == hash { if bestpeer.parentHash == hash {
if self.hasBlock(bestpeer.currentBlockHash) { if self.hasBlock(bestpeer.currentBlockHash) {
bestpeer.lock.RUnlock()
return return
} }
/* /*
@ -396,6 +398,7 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st
if entry := self.get(bestpeer.currentBlockHash); entry == nil { if entry := self.get(bestpeer.currentBlockHash); entry == nil {
plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s) head section starting from [%s] ", peerId, hex(bestpeer.currentBlockHash), hex(bestpeer.parentHash)) plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s) head section starting from [%s] ", peerId, hex(bestpeer.currentBlockHash), hex(bestpeer.parentHash))
// if head block is not yet in the pool, create entry and start node list for section // if head block is not yet in the pool, create entry and start node list for section
node := &node{ node := &node{
hash: bestpeer.currentBlockHash, hash: bestpeer.currentBlockHash,
block: bestpeer.currentBlock, block: bestpeer.currentBlock,
@ -421,7 +424,7 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st
} }
// the switch channel signals peerswitch event // the switch channel signals peerswitch event
switchC := bestpeer.switchC switchC := bestpeer.switchC
bestpeer.lock.Unlock() bestpeer.lock.RUnlock()
// iterate over hashes coming from peer (first round we have hash set above) // iterate over hashes coming from peer (first round we have hash set above)
LOOP: LOOP:
@ -547,8 +550,10 @@ LOOP:
In this case no activation should happen In this case no activation should happen
*/ */
if parent != nil && !peerswitch { if parent != nil && !peerswitch {
self.activateChain(parent, bestpeer, nil) bestpeer.lock.RLock()
self.activateChain(parent, bestpeer, bestpeer.switchC, nil)
plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s): parent section [%s]", peerId, hex(bestpeer.currentBlockHash), sectionhex(parent)) plog.DebugDetailf("AddBlockHashes: peer <%s> (head: %s): parent section [%s]", peerId, hex(bestpeer.currentBlockHash), sectionhex(parent))
bestpeer.lock.RUnlock()
} }
/* /*
@ -622,53 +627,60 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
self.status.lock.Unlock() self.status.lock.Unlock()
entry := self.get(hash) entry := self.get(hash)
blockIsCurrentHead := false
sender.lock.RLock()
currentBlockHash := sender.currentBlockHash
currentBlock := sender.currentBlock
currentBlockC := sender.currentBlockC
switchC := sender.switchC
sender.lock.RUnlock()
// a peer's current head block is appearing the first time // a peer's current head block is appearing the first time
if hash == sender.currentBlockHash { if hash == currentBlockHash {
if sender.currentBlock == nil { // this happens when block came in a newblock message but
plog.Debugf("AddBlock: add head block %s for peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) // also if sent in a blockmsg (for instance, if we requested, only if we
// dont apply on blockrequests the restriction of flood control)
blockIsCurrentHead = true
if currentBlock == nil {
sender.lock.Lock()
sender.setChainInfoFromBlock(block) sender.setChainInfoFromBlock(block)
sender.lock.Unlock()
self.status.lock.Lock() self.status.lock.Lock()
self.status.values.BlockHashes++ self.status.values.BlockHashes++
self.status.values.Blocks++ self.status.values.Blocks++
self.status.values.BlocksInPool++ self.status.values.BlocksInPool++
self.status.lock.Unlock() 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 // signal to head section process
sender.currentBlockC <- block select {
case currentBlockC <- block:
case <-switchC:
}
} else {
plog.DebugDetailf("AddBlock: head block %s for peer <%s> (head: %s) already known", hex(hash), peerId, hex(currentBlockHash))
} }
} else { } else {
plog.DebugDetailf("AddBlock: block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) plog.DebugDetailf("AddBlock: block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(currentBlockHash))
sender.lock.Lock()
// update peer chain info if more recent than what we registered
if block.Td != nil && block.Td.Cmp(sender.td) > 0 {
sender.td = block.Td
sender.currentBlockHash = block.Hash()
sender.parentHash = block.ParentHash()
sender.currentBlock = block
sender.headSection = nil
}
sender.lock.Unlock()
/* @zelig !!! /* @zelig !!!
requested 5 hashes from both A & B. A responds sooner then B, process blocks. Close section. requested 5 hashes from both A & B. A responds sooner then B, process blocks. Close section.
delayed B sends you block ... UNREQUESTED. Blocked delayed B sends you block ... UNREQUESTED. Blocked
if entry == nil { if entry == nil {
plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
sender.addError(ErrUnrequestedBlock, "%x", hash) sender.addError(ErrUnrequestedBlock, "%x", hash)
self.status.lock.Lock() self.status.lock.Lock()
self.status.badPeers[peerId]++ self.status.badPeers[peerId]++
self.status.lock.Unlock() self.status.lock.Unlock()
return return
} }
*/ */
} }
if entry == nil { if entry == nil {
// FIXME: here check the cache find or create node -
// put peer as blockBy!
return return
} }
@ -676,10 +688,22 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
node.lock.Lock() node.lock.Lock()
defer node.lock.Unlock() defer node.lock.Unlock()
// register peer on node as source
if node.peers == nil {
node.peers = make(map[string]bool)
}
FoundBlockCurrentHead, found := node.peers[sender.id]
if !found || FoundBlockCurrentHead {
// if found but not FoundBlockCurrentHead, then no update
// necessary (||)
node.peers[sender.id] = blockIsCurrentHead
// for those that are false, TD will update their head
// for those that are true, TD is checked !
// this is checked at the time of TD calculation in checkTD
}
// check if block already received // check if block already received
if node.block != nil { 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) plog.DebugDetailf("AddBlock: block %s from peer <%s> (head: %s) already sent by <%s> ", hex(hash), peerId, hex(sender.currentBlockHash), node.blockBy)
return
} }
// check if block is already inserted in the blockchain // check if block is already inserted in the blockchain
@ -690,6 +714,8 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
/* /*
@zelig needs discussing @zelig needs discussing
Viktor: pow check can be delayed in a go routine and therefore cache
creation is not blocking
// validate block for PoW // validate block for PoW
if !self.verifyPoW(block) { if !self.verifyPoW(block) {
plog.Warnf("AddBlock: invalid PoW on block %s from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) plog.Warnf("AddBlock: invalid PoW on block %s from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
@ -705,7 +731,6 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
node.block = block node.block = block
node.blockBy = peerId node.blockBy = peerId
node.td = block.Td // optional field
self.status.lock.Lock() self.status.lock.Lock()
self.status.values.Blocks++ self.status.values.Blocks++
@ -719,11 +744,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
It activates the section process on incomplete sections with peer. 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. 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[common.Hash]*section) { func (self *BlockPool) activateChain(sec *section, p *peer, switchC chan bool, connected map[common.Hash]*section) {
p.lock.RLock()
switchC := p.switchC
p.lock.RUnlock()
var i int var i int
@ -766,13 +787,14 @@ LOOP:
// check if block's actual TD (calculated after successful insertChain) is identical to TD advertised for peer's head block. // 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) { func (self *BlockPool) checkTD(nodes ...*node) {
for _, n := range nodes { for _, n := range nodes {
if n.td != nil { // skip check if queued future block
if n.td != nil && !n.block.Queued() {
plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td) plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td)
if n.td.Cmp(n.block.Td) != 0 { if n.td.Cmp(n.block.Td) != 0 {
//self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash) self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash)
//self.status.lock.Lock() self.status.lock.Lock()
//self.status.badPeers[n.blockBy]++ self.status.badPeers[n.blockBy]++
//self.status.lock.Unlock() self.status.lock.Unlock()
} }
} }
} }

@ -7,6 +7,10 @@ import (
"github.com/ethereum/go-ethereum/blockpool/test" "github.com/ethereum/go-ethereum/blockpool/test"
) )
func init() {
test.LogInit()
}
// using the mock framework in blockpool_util_test // using the mock framework in blockpool_util_test
// we test various scenarios here // we test various scenarios here

@ -87,7 +87,7 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error {
var ok bool var ok bool
for _, block := range blocks { for _, block := range blocks {
child = self.hashPool.HashesToIndexes([]common.Hash{block.Hash()})[0] child = self.hashPool.HashesToIndexes([]common.Hash{block.Hash()})[0]
var td int td := child
if self.tds != nil { if self.tds != nil {
td, ok = self.tds[child] td, ok = self.tds[child]
} }

@ -39,6 +39,8 @@ func TestInvalidBlock(t *testing.T) {
} }
func TestVerifyPoW(t *testing.T) { func TestVerifyPoW(t *testing.T) {
t.Skip() // :FIXME:
test.LogInit() test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t) _, blockPool, blockPoolTester := newTestBlockPool(t)
blockPoolTester.blockChain[0] = nil blockPoolTester.blockChain[0] = nil
@ -84,6 +86,8 @@ func TestVerifyPoW(t *testing.T) {
} }
func TestUnrequestedBlock(t *testing.T) { func TestUnrequestedBlock(t *testing.T) {
t.Skip() // :FIXME:
test.LogInit() test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t) _, blockPool, blockPoolTester := newTestBlockPool(t)
blockPoolTester.blockChain[0] = nil blockPoolTester.blockChain[0] = nil
@ -124,8 +128,6 @@ func TestErrInsufficientChainInfo(t *testing.T) {
} }
func TestIncorrectTD(t *testing.T) { func TestIncorrectTD(t *testing.T) {
t.Skip() // @zelig this one requires fixing for the TD
test.LogInit() test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t) _, blockPool, blockPoolTester := newTestBlockPool(t)
blockPoolTester.blockChain[0] = nil blockPoolTester.blockChain[0] = nil
@ -152,6 +154,45 @@ func TestIncorrectTD(t *testing.T) {
} }
} }
func TestSkipIncorrectTDonFutureBlocks(t *testing.T) {
// t.Skip() // @zelig this one requires fixing for the TD
test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t)
blockPoolTester.blockChain[0] = nil
blockPoolTester.initRefBlockChain(3)
blockPool.insertChain = func(blocks types.Blocks) error {
err := blockPoolTester.insertChain(blocks)
if err == nil {
for _, block := range blocks {
if block.Td.Cmp(common.Big3) == 0 {
block.Td = common.Big3
block.SetQueued(true)
break
}
}
}
return err
}
blockPool.Start()
peer1 := blockPoolTester.newPeer("peer1", 3, 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) > 0 {
t.Errorf("expected no error, got %v (1 of %v)", peer1.peerErrors[0], len(peer1.peerErrors))
}
}
func TestPeerSuspension(t *testing.T) { func TestPeerSuspension(t *testing.T) {
test.LogInit() test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t) _, blockPool, blockPoolTester := newTestBlockPool(t)

@ -57,7 +57,8 @@ type peer struct {
// peers is the component keeping a record of peers in a hashmap // peers is the component keeping a record of peers in a hashmap
// //
type peers struct { type peers struct {
lock sync.RWMutex lock sync.RWMutex
bllock sync.Mutex
bp *BlockPool bp *BlockPool
errors *errs.Errors errors *errs.Errors
@ -109,15 +110,15 @@ func (self *peers) peerError(id string, code int, format string, params ...inter
// record time of offence in blacklist to implement suspension for PeerSuspensionInterval // record time of offence in blacklist to implement suspension for PeerSuspensionInterval
func (self *peers) addToBlacklist(id string) { func (self *peers) addToBlacklist(id string) {
self.lock.Lock() self.bllock.Lock()
defer self.lock.Unlock() defer self.bllock.Unlock()
self.blacklist[id] = time.Now() self.blacklist[id] = time.Now()
} }
// suspended checks if peer is still suspended // suspended checks if peer is still suspended, caller should hold peers.lock
func (self *peers) suspended(id string) (s bool) { func (self *peers) suspended(id string) (s bool) {
self.lock.Lock() self.bllock.Lock()
defer self.lock.Unlock() defer self.bllock.Unlock()
if suspendedAt, ok := self.blacklist[id]; ok { if suspendedAt, ok := self.blacklist[id]; ok {
if s = suspendedAt.Add(self.bp.Config.PeerSuspensionInterval).After(time.Now()); !s { if s = suspendedAt.Add(self.bp.Config.PeerSuspensionInterval).After(time.Now()); !s {
// no longer suspended, delete entry // no longer suspended, delete entry
@ -142,9 +143,8 @@ func (self *peer) setChainInfo(td *big.Int, c common.Hash) {
self.headSection = nil self.headSection = nil
} }
// caller must hold peer lock
func (self *peer) setChainInfoFromBlock(block *types.Block) { func (self *peer) setChainInfoFromBlock(block *types.Block) {
self.lock.Lock()
defer self.lock.Unlock()
// use the optional TD to update peer td, this helps second best peer selection // use the optional TD to update peer td, this helps second best peer selection
// in case best peer is lost // in case best peer is lost
if block.Td != nil && block.Td.Cmp(self.td) > 0 { if block.Td != nil && block.Td.Cmp(self.td) > 0 {
@ -155,16 +155,12 @@ func (self *peer) setChainInfoFromBlock(block *types.Block) {
self.currentBlock = block self.currentBlock = block
self.headSection = nil self.headSection = nil
} }
self.bp.wg.Add(1)
go func() {
self.currentBlockC <- block
self.bp.wg.Done()
}()
} }
// distribute block request among known peers // distribute block request among known peers
func (self *peers) requestBlocks(attempts int, hashes []common.Hash) { func (self *peers) requestBlocks(attempts int, hashes []common.Hash) {
self.lock.RLock() self.lock.RLock()
defer self.lock.RUnlock() defer self.lock.RUnlock()
peerCount := len(self.peers) peerCount := len(self.peers)
// on first attempt use the best peer // on first attempt use the best peer
@ -210,13 +206,14 @@ func (self *peers) addPeer(
peerError func(*errs.Error), peerError func(*errs.Error),
) (best bool, suspended bool) { ) (best bool, suspended bool) {
self.lock.Lock()
defer self.lock.Unlock()
var previousBlockHash common.Hash var previousBlockHash common.Hash
if self.suspended(id) { if self.suspended(id) {
suspended = true suspended = true
return return
} }
self.lock.Lock()
defer self.lock.Unlock()
p, found := self.peers[id] p, found := self.peers[id]
if found { if found {
// when called on an already connected peer, it means a newBlockMsg is received // when called on an already connected peer, it means a newBlockMsg is received
@ -260,7 +257,7 @@ func (self *peers) addPeer(
p.headSectionC <- nil p.headSectionC <- nil
if entry := self.bp.get(previousBlockHash); entry != nil { if entry := self.bp.get(previousBlockHash); entry != nil {
plog.DebugDetailf("addPeer: <%s> previous head : %v found in pool, activate", id, hex(previousBlockHash)) plog.DebugDetailf("addPeer: <%s> previous head : %v found in pool, activate", id, hex(previousBlockHash))
self.bp.activateChain(entry.section, p, nil) self.bp.activateChain(entry.section, p, p.switchC, nil)
p.sections = append(p.sections, previousBlockHash) p.sections = append(p.sections, previousBlockHash)
} }
} }
@ -270,8 +267,8 @@ func (self *peers) addPeer(
currentTD := self.bp.getTD() currentTD := self.bp.getTD()
bestpeer := self.best bestpeer := self.best
if bestpeer != nil { if bestpeer != nil {
bestpeer.lock.Lock() bestpeer.lock.RLock()
defer bestpeer.lock.Unlock() defer bestpeer.lock.RUnlock()
currentTD = self.best.td currentTD = self.best.td
} }
if td.Cmp(currentTD) > 0 { if td.Cmp(currentTD) > 0 {
@ -367,14 +364,14 @@ func (self *BlockPool) switchPeer(oldp, newp *peer) {
if connected[hash] == nil { if connected[hash] == nil {
// if not deleted, then reread from pool (it can be orphaned top half of a split section) // if not deleted, then reread from pool (it can be orphaned top half of a split section)
if entry := self.get(hash); entry != nil { if entry := self.get(hash); entry != nil {
self.activateChain(entry.section, newp, connected) self.activateChain(entry.section, newp, newp.switchC, connected)
connected[hash] = entry.section connected[hash] = entry.section
sections = append(sections, hash) sections = append(sections, hash)
} }
} }
} }
plog.DebugDetailf("<%s> section processes (%v non-contiguous sequences, was %v before)", newp.id, len(sections), len(newp.sections)) plog.DebugDetailf("<%s> section processes (%v non-contiguous sequences, was %v before)", newp.id, len(sections), len(newp.sections))
// need to lock now that newp is exposed to section processes // need to lock now that newp is exposed to section processesr
newp.lock.Lock() newp.lock.Lock()
newp.sections = sections newp.sections = sections
newp.lock.Unlock() newp.lock.Unlock()
@ -462,6 +459,8 @@ func (self *peer) getCurrentBlock(currentBlock *types.Block) {
} }
func (self *peer) getBlockHashes() bool { func (self *peer) getBlockHashes() bool {
self.lock.Lock()
defer self.lock.Unlock()
//if connecting parent is found //if connecting parent is found
if self.bp.hasBlock(self.parentHash) { if self.bp.hasBlock(self.parentHash) {
plog.DebugDetailf("HeadSection: <%s> parent block %s found in blockchain", self.id, hex(self.parentHash)) plog.DebugDetailf("HeadSection: <%s> parent block %s found in blockchain", self.id, hex(self.parentHash))
@ -475,10 +474,11 @@ func (self *peer) getBlockHashes() bool {
self.bp.status.badPeers[self.id]++ self.bp.status.badPeers[self.id]++
} else { } else {
// XXX added currentBlock check (?) // XXX added currentBlock check (?)
if self.currentBlock != nil && self.currentBlock.Td != nil { if self.currentBlock != nil && self.currentBlock.Td != nil && !self.currentBlock.Queued() {
plog.DebugDetailf("HeadSection: <%s> inserted %s to blockchain... check TD %v =?= %v", self.id, hex(self.parentHash), self.td, self.currentBlock.Td)
if self.td.Cmp(self.currentBlock.Td) != 0 { if self.td.Cmp(self.currentBlock.Td) != 0 {
//self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash) self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash)
//self.bp.status.badPeers[self.id]++ self.bp.status.badPeers[self.id]++
} }
} }
headKey := self.parentHash headKey := self.parentHash
@ -504,7 +504,7 @@ func (self *peer) getBlockHashes() bool {
self.bp.newSection([]*node{n}).activate(self) self.bp.newSection([]*node{n}).activate(self)
} else { } else {
plog.DebugDetailf("HeadSection: <%s> connecting parent %s found in pool...head section [%s] exists...not requesting hashes", self.id, hex(self.parentHash), sectionhex(parent.section)) plog.DebugDetailf("HeadSection: <%s> connecting parent %s found in pool...head section [%s] exists...not requesting hashes", self.id, hex(self.parentHash), sectionhex(parent.section))
self.bp.activateChain(parent.section, self, nil) self.bp.activateChain(parent.section, self, self.switchC, nil)
} }
} else { } else {
plog.DebugDetailf("HeadSection: <%s> section [%s] requestBlockHashes", self.id, sectionhex(self.headSection)) plog.DebugDetailf("HeadSection: <%s> section [%s] requestBlockHashes", self.id, sectionhex(self.headSection))
@ -528,6 +528,7 @@ func (self *peer) run() {
self.lock.RLock() self.lock.RLock()
switchC := self.switchC switchC := self.switchC
plog.Debugf("HeadSection: <%s> section process for head %s started", self.id, hex(self.currentBlockHash))
self.lock.RUnlock() self.lock.RUnlock()
self.blockHashesRequestTimer = nil self.blockHashesRequestTimer = nil
@ -570,7 +571,6 @@ LOOP:
self.bp.status.badPeers[self.id]++ self.bp.status.badPeers[self.id]++
self.bp.status.lock.Unlock() self.bp.status.lock.Unlock()
// there is no persistence here, so GC will just take care of cleaning up // there is no persistence here, so GC will just take care of cleaning up
break LOOP
// signal for peer switch, quit // signal for peer switch, quit
case <-switchC: case <-switchC:
@ -593,9 +593,9 @@ LOOP:
self.bp.status.badPeers[self.id]++ self.bp.status.badPeers[self.id]++
self.bp.status.lock.Unlock() self.bp.status.lock.Unlock()
plog.Debugf("HeadSection: <%s> (headsection [%s]) quit channel closed : timed out without providing new blocks...quitting", self.id, sectionhex(self.headSection)) plog.Debugf("HeadSection: <%s> (headsection [%s]) quit channel closed : timed out without providing new blocks...quitting", self.id, sectionhex(self.headSection))
break LOOP
} }
} }
if !self.idle { if !self.idle {
self.idle = true self.idle = true
self.bp.wg.Done() self.bp.wg.Done()

@ -144,7 +144,8 @@ func TestAddPeer(t *testing.T) {
blockPool.Stop() blockPool.Stop()
} }
func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) { func TestPeerPromotionByTdOnBlock(t *testing.T) {
t.Skip()
test.LogInit() test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t) _, blockPool, blockPoolTester := newTestBlockPool(t)
blockPoolTester.blockChain[0] = nil blockPoolTester.blockChain[0] = nil
@ -168,13 +169,8 @@ func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) {
best = peer2.AddPeer() best = peer2.AddPeer()
peer2.serveBlocks(3, 4) peer2.serveBlocks(3, 4)
peer2.serveBlockHashes(4, 3, 2, 1) peer2.serveBlockHashes(4, 3, 2, 1)
hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3}) // hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3})
peer1.waitBlocksRequests(3) peer1.serveBlocks(2, 3)
blockPool.AddBlock(&types.Block{
HeaderHash: common.Hash(hashes[1]),
ParentHeaderHash: common.Hash(hashes[0]),
Td: common.Big3,
}, "peer1")
blockPool.RemovePeer("peer2") blockPool.RemovePeer("peer2")
if blockPool.peers.best.id != "peer1" { if blockPool.peers.best.id != "peer1" {

@ -489,7 +489,7 @@ func (self *section) blockHashesRequest() {
// activate parent section with this peer // activate parent section with this peer
// but only if not during switch mode // but only if not during switch mode
plog.DebugDetailf("[%s] parent section [%s] activated\n", sectionhex(self), sectionhex(parentSection)) plog.DebugDetailf("[%s] parent section [%s] activated\n", sectionhex(self), sectionhex(parentSection))
self.bp.activateChain(parentSection, self.peer, nil) self.bp.activateChain(parentSection, self.peer, self.peer.switchC, nil)
// if not root of chain, switch off // if not root of chain, switch off
plog.DebugDetailf("[%s] parent found, hash requests deactivated (after %v total attempts)\n", sectionhex(self), self.blockHashesRequests) plog.DebugDetailf("[%s] parent found, hash requests deactivated (after %v total attempts)\n", sectionhex(self), self.blockHashesRequests)
self.blockHashesRequestTimer = nil self.blockHashesRequestTimer = nil

@ -60,6 +60,8 @@ func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err
} }
func TestBlockPoolStatus(t *testing.T) { func TestBlockPoolStatus(t *testing.T) {
t.Skip() // :FIXME:
test.LogInit() test.LogInit()
var err error var err error
n := 3 n := 3
@ -87,7 +89,7 @@ func testBlockPoolStatus(t *testing.T) (err error) {
delete(blockPoolTester.refBlockChain, 6) delete(blockPoolTester.refBlockChain, 6)
blockPool.Start() blockPool.Start()
defer blockPool.Stop()
blockPoolTester.tds = make(map[int]int) blockPoolTester.tds = make(map[int]int)
blockPoolTester.tds[9] = 1 blockPoolTester.tds[9] = 1
blockPoolTester.tds[11] = 3 blockPoolTester.tds[11] = 3
@ -107,6 +109,7 @@ func testBlockPoolStatus(t *testing.T) (err error) {
} }
peer1.AddPeer() peer1.AddPeer()
expected = []int{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0} expected = []int{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0}
err = checkStatus(nil, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
@ -242,6 +245,8 @@ func testBlockPoolStatus(t *testing.T) (err error) {
peer3.serveBlocks(0, 1) peer3.serveBlocks(0, 1)
blockPool.Wait(waitTimeout) blockPool.Wait(waitTimeout)
time.Sleep(200 * time.Millisecond) time.Sleep(200 * time.Millisecond)
blockPool.Stop()
expected = []int{14, 3, 11, 3, 8, 4, 1, 8, 4, 3, 4, 3, 1} expected = []int{14, 3, 11, 3, 8, 4, 1, 8, 4, 3, 4, 3, 1}
err = checkStatus(nil, blockPool, false, expected) err = checkStatus(nil, blockPool, false, expected)
if err != nil { if err != nil {

@ -463,6 +463,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
// Do not penelise on future block. We'll need a block queue eventually that will queue // Do not penelise on future block. We'll need a block queue eventually that will queue
// future block for future use // future block for future use
if err == BlockFutureErr { if err == BlockFutureErr {
block.SetQueued(true)
self.futureBlocks.Push(block) self.futureBlocks.Push(block)
stats.queued++ stats.queued++
continue continue

@ -97,6 +97,7 @@ type Block struct {
uncles []*Header uncles []*Header
transactions Transactions transactions Transactions
Td *big.Int Td *big.Int
queued bool // flag for blockpool to skip TD check
receipts Receipts receipts Receipts
} }
@ -268,6 +269,9 @@ func (self *Block) SetNonce(nonce uint64) {
self.header.SetNonce(nonce) self.header.SetNonce(nonce)
} }
func (self *Block) Queued() bool { return self.queued }
func (self *Block) SetQueued(q bool) { self.queued = q }
func (self *Block) Bloom() Bloom { return self.header.Bloom } func (self *Block) Bloom() Bloom { return self.header.Bloom }
func (self *Block) Coinbase() common.Address { return self.header.Coinbase } func (self *Block) Coinbase() common.Address { return self.header.Coinbase }
func (self *Block) Time() int64 { return int64(self.header.Time) } func (self *Block) Time() int64 { return int64(self.header.Time) }

Loading…
Cancel
Save