diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 1b9b7d01b2..206c4cc7e2 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -268,8 +268,14 @@ out: chunk := d.queue.get(peer, maxBlockFetch) if chunk != nil { //fmt.Println("fetching for", peer.id) - // Fetch the chunk. - peer.fetch(chunk) + // Fetch the chunk and check for error. If the peer was somehow + // already fetching a chunk due to a bug, it will be returned to + // the queue + if err := peer.fetch(chunk); err != nil { + // log for tracing + glog.V(logger.Debug).Infof("peer %s received double work (state = %v)\n", peer.id, peer.state) + d.queue.put(chunk.hashes) + } } } atomic.StoreInt32(&d.downloadingBlocks, 1) diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go index 486c09e38b..318da59b7c 100644 --- a/eth/downloader/peer.go +++ b/eth/downloader/peer.go @@ -1,6 +1,7 @@ package downloader import ( + "errors" "math/big" "sync" @@ -31,10 +32,14 @@ func newPeer(id string, td *big.Int, hash common.Hash, getHashes hashFetcherFn, } // fetch a chunk using the peer -func (p *peer) fetch(chunk *chunk) { +func (p *peer) fetch(chunk *chunk) error { p.mu.Lock() defer p.mu.Unlock() + if p.state == workingState { + return errors.New("peer already fetching chunk") + } + // set working state p.state = workingState // convert the set to a fetchable slice @@ -45,4 +50,6 @@ func (p *peer) fetch(chunk *chunk) { return true }) p.getBlocks(hashes) + + return nil }