Commit 6adbaabc authored by Péter Szilágyi's avatar Péter Szilágyi

eth, eth/downloader: don't report stall if fetcher filled the block

parent cc27be9d
...@@ -21,6 +21,7 @@ import ( ...@@ -21,6 +21,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"math" "math"
"math/big"
"math/rand" "math/rand"
"sync" "sync"
"sync/atomic" "sync/atomic"
...@@ -232,10 +233,10 @@ func (d *Downloader) UnregisterPeer(id string) error { ...@@ -232,10 +233,10 @@ func (d *Downloader) UnregisterPeer(id string) error {
// Synchronise tries to sync up our local block chain with a remote peer, both // Synchronise tries to sync up our local block chain with a remote peer, both
// adding various sanity checks as well as wrapping it with various log entries. // adding various sanity checks as well as wrapping it with various log entries.
func (d *Downloader) Synchronise(id string, head common.Hash) { func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int) {
glog.V(logger.Detail).Infof("Attempting synchronisation: %v, 0x%x", id, head) glog.V(logger.Detail).Infof("Attempting synchronisation: %v, head 0x%x, TD %v", id, head[:4], td)
switch err := d.synchronise(id, head); err { switch err := d.synchronise(id, head, td); err {
case nil: case nil:
glog.V(logger.Detail).Infof("Synchronisation completed") glog.V(logger.Detail).Infof("Synchronisation completed")
...@@ -257,7 +258,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash) { ...@@ -257,7 +258,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash) {
// synchronise will select the peer and use it for synchronising. If an empty string is given // synchronise will select the peer and use it for synchronising. If an empty string is given
// it will use the best peer possible and synchronize if it's TD is higher than our own. If any of the // it will use the best peer possible and synchronize if it's TD is higher than our own. If any of the
// checks fail an error will be returned. This method is synchronous // checks fail an error will be returned. This method is synchronous
func (d *Downloader) synchronise(id string, hash common.Hash) error { func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int) error {
// Mock out the synchonisation if testing // Mock out the synchonisation if testing
if d.synchroniseMock != nil { if d.synchroniseMock != nil {
return d.synchroniseMock(id, hash) return d.synchroniseMock(id, hash)
...@@ -295,7 +296,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash) error { ...@@ -295,7 +296,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash) error {
if p == nil { if p == nil {
return errUnknownPeer return errUnknownPeer
} }
return d.syncWithPeer(p, hash) return d.syncWithPeer(p, hash, td)
} }
// Has checks if the downloader knows about a particular hash, meaning that its // Has checks if the downloader knows about a particular hash, meaning that its
...@@ -306,7 +307,7 @@ func (d *Downloader) Has(hash common.Hash) bool { ...@@ -306,7 +307,7 @@ func (d *Downloader) Has(hash common.Hash) bool {
// syncWithPeer starts a block synchronization based on the hash chain from the // syncWithPeer starts a block synchronization based on the hash chain from the
// specified peer and head hash. // specified peer and head hash.
func (d *Downloader) syncWithPeer(p *peer, hash common.Hash) (err error) { func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err error) {
d.mux.Post(StartEvent{}) d.mux.Post(StartEvent{})
defer func() { defer func() {
// reset on error // reset on error
...@@ -335,7 +336,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash) (err error) { ...@@ -335,7 +336,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash) (err error) {
return err return err
} }
errc := make(chan error, 2) errc := make(chan error, 2)
go func() { errc <- d.fetchHashes(p, number+1) }() go func() { errc <- d.fetchHashes(p, td, number+1) }()
go func() { errc <- d.fetchBlocks(number + 1) }() go func() { errc <- d.fetchBlocks(number + 1) }()
// If any fetcher fails, cancel the other // If any fetcher fails, cancel the other
...@@ -788,7 +789,7 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) { ...@@ -788,7 +789,7 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) {
// fetchHashes keeps retrieving hashes from the requested number, until no more // fetchHashes keeps retrieving hashes from the requested number, until no more
// are returned, potentially throttling on the way. // are returned, potentially throttling on the way.
func (d *Downloader) fetchHashes(p *peer, from uint64) error { func (d *Downloader) fetchHashes(p *peer, td *big.Int, from uint64) error {
glog.V(logger.Debug).Infof("%v: downloading hashes from #%d", p, from) glog.V(logger.Debug).Infof("%v: downloading hashes from #%d", p, from)
// Create a timeout timer, and the associated hash fetcher // Create a timeout timer, and the associated hash fetcher
...@@ -827,8 +828,19 @@ func (d *Downloader) fetchHashes(p *peer, from uint64) error { ...@@ -827,8 +828,19 @@ func (d *Downloader) fetchHashes(p *peer, from uint64) error {
case d.processCh <- false: case d.processCh <- false:
case <-d.cancelCh: case <-d.cancelCh:
} }
// Error out if no hashes were retrieved at all // If no hashes were retrieved at all, the peer violated it's TD promise that it had a
if !gotHashes { // better chain compared to ours. The only exception is if it's promised blocks were
// already imported by other means (e.g. fecher):
//
// R <remote peer>, L <local node>: Both at block 10
// R: Mine block 11, and propagate it to L
// L: Queue block 11 for import
// L: Notice that R's head and TD increased compared to ours, start sync
// L: Import of block 11 finishes
// L: Sync begins, and finds common ancestor at 11
// L: Request new hashes up from 11 (R's TD was higher, it must have something)
// R: Nothing to give
if !gotHashes && td.Cmp(d.headBlock().Td) > 0 {
return errStallingPeer return errStallingPeer
} }
return nil return nil
......
This diff is collapsed.
...@@ -164,5 +164,5 @@ func (pm *ProtocolManager) synchronise(peer *peer) { ...@@ -164,5 +164,5 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
return return
} }
// Otherwise try to sync with the downloader // Otherwise try to sync with the downloader
pm.downloader.Synchronise(peer.id, peer.Head()) pm.downloader.Synchronise(peer.id, peer.Head(), peer.Td())
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment