eth/downloader: don't block hash deliveries while pulling blocks

This commit is contained in:
Péter Szilágyi 2015-06-02 15:57:07 +03:00
parent 9da0232eef
commit 6d497f61c6

@ -418,6 +418,9 @@ out:
case <-d.cancelCh: case <-d.cancelCh:
return errCancelBlockFetch return errCancelBlockFetch
case <-d.hashCh:
// Out of bounds hashes received, ignore them
case blockPack := <-d.blockCh: case blockPack := <-d.blockCh:
// Short circuit if it's a stale cross check // Short circuit if it's a stale cross check
if len(blockPack.blocks) == 1 { if len(blockPack.blocks) == 1 {
@ -472,30 +475,21 @@ out:
glog.V(logger.Detail).Infof("%s: delivery partially failed: %v", peer, err) glog.V(logger.Detail).Infof("%s: delivery partially failed: %v", peer, err)
} }
} }
case <-ticker.C: case <-ticker.C:
// Check for bad peers. Bad peers may indicate a peer not responding // Short circuit if we lost all our peers
// to a `getBlocks` message. A timeout of 5 seconds is set. Peers if d.peers.Len() == 0 {
// that badly or poorly behave are removed from the peer set (not banned). return errNoPeers
// Bad peers are excluded from the available peer set and therefor won't be }
// reused. XXX We could re-introduce peers after X time. // Check for block request timeouts and demote the responsible peers
badPeers := d.queue.Expire(blockHardTTL) badPeers := d.queue.Expire(blockHardTTL)
for _, pid := range badPeers { for _, pid := range badPeers {
// XXX We could make use of a reputation system here ranking peers
// in their performance
// 1) Time for them to respond;
// 2) Measure their speed;
// 3) Amount and availability.
if peer := d.peers.Peer(pid); peer != nil { if peer := d.peers.Peer(pid); peer != nil {
peer.Demote() peer.Demote()
glog.V(logger.Detail).Infof("%s: block delivery timeout", peer) glog.V(logger.Detail).Infof("%s: block delivery timeout", peer)
} }
} }
// After removing bad peers make sure we actually have sufficient peer left to keep downloading // If there are unrequested hashes left start fetching from the available peers
if d.peers.Len() == 0 {
return errNoPeers
}
// If there are unrequested hashes left start fetching
// from the available peers.
if d.queue.Pending() > 0 { if d.queue.Pending() > 0 {
// Throttle the download if block cache is full and waiting processing // Throttle the download if block cache is full and waiting processing
if d.queue.Throttle() { if d.queue.Throttle() {
@ -565,7 +559,7 @@ func (d *Downloader) banBlocks(peerId string, head common.Hash) error {
return err return err
} }
// Wait a bit for the reply to arrive, and ban if done so // Wait a bit for the reply to arrive, and ban if done so
timeout := time.After(blockTTL) timeout := time.After(blockHardTTL)
for { for {
select { select {
case <-d.cancelCh: case <-d.cancelCh:
@ -574,6 +568,9 @@ func (d *Downloader) banBlocks(peerId string, head common.Hash) error {
case <-timeout: case <-timeout:
return ErrTimeout return ErrTimeout
case <-d.hashCh:
// Out of bounds hashes received, ignore them
case blockPack := <-d.blockCh: case blockPack := <-d.blockCh:
blocks := blockPack.blocks blocks := blockPack.blocks