eth/downloader: reject peer registration if head is banned

This commit is contained in:
Péter Szilágyi 2015-06-08 14:46:31 +03:00
parent 63c6cedb14
commit c4f224932f

@ -36,6 +36,7 @@ var (
errUnknownPeer = errors.New("peer is unknown or unhealthy") errUnknownPeer = errors.New("peer is unknown or unhealthy")
ErrBadPeer = errors.New("action from bad peer ignored") ErrBadPeer = errors.New("action from bad peer ignored")
ErrStallingPeer = errors.New("peer is stalling") ErrStallingPeer = errors.New("peer is stalling")
errBannedHead = errors.New("peer head hash already banned")
errNoPeers = errors.New("no peers to keep download active") errNoPeers = errors.New("no peers to keep download active")
ErrPendingQueue = errors.New("pending items in queue") ErrPendingQueue = errors.New("pending items in queue")
ErrTimeout = errors.New("timeout") ErrTimeout = errors.New("timeout")
@ -72,11 +73,10 @@ type crossCheck struct {
type Downloader struct { type Downloader struct {
mux *event.TypeMux mux *event.TypeMux
mu sync.RWMutex
queue *queue // Scheduler for selecting the hashes to download queue *queue // Scheduler for selecting the hashes to download
peers *peerSet // Set of active peers from which download can proceed peers *peerSet // Set of active peers from which download can proceed
checks map[common.Hash]*crossCheck // Pending cross checks to verify a hash chain checks map[common.Hash]*crossCheck // Pending cross checks to verify a hash chain
banned *set.SetNonTS // Set of hashes we've received and banned banned *set.Set // Set of hashes we've received and banned
// Callbacks // Callbacks
hasBlock hashCheckFn hasBlock hashCheckFn
@ -114,7 +114,7 @@ func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock getBlockFn) *Downloa
blockCh: make(chan blockPack, 1), blockCh: make(chan blockPack, 1),
} }
// Inject all the known bad hashes // Inject all the known bad hashes
downloader.banned = set.NewNonTS() downloader.banned = set.New()
for hash, _ := range core.BadHashes { for hash, _ := range core.BadHashes {
downloader.banned.Add(hash) downloader.banned.Add(hash)
} }
@ -133,6 +133,12 @@ func (d *Downloader) Synchronising() bool {
// RegisterPeer injects a new download peer into the set of block source to be // RegisterPeer injects a new download peer into the set of block source to be
// used for fetching hashes and blocks from. // used for fetching hashes and blocks from.
func (d *Downloader) RegisterPeer(id string, head common.Hash, getHashes hashFetcherFn, getBlocks blockFetcherFn) error { func (d *Downloader) RegisterPeer(id string, head common.Hash, getHashes hashFetcherFn, getBlocks blockFetcherFn) error {
// If the peer wants to send a banned hash, reject
if d.banned.Has(head) {
glog.V(logger.Debug).Infoln("Register rejected, head hash banned:", id)
return errBannedHead
}
// Otherwise try to construct and register the peer
glog.V(logger.Detail).Infoln("Registering peer", id) glog.V(logger.Detail).Infoln("Registering peer", id)
if err := d.peers.Register(newPeer(id, head, getHashes, getBlocks)); err != nil { if err := d.peers.Register(newPeer(id, head, getHashes, getBlocks)); err != nil {
glog.V(logger.Error).Infoln("Register failed:", err) glog.V(logger.Error).Infoln("Register failed:", err)
@ -199,6 +205,8 @@ func (d *Downloader) TakeBlocks() []*Block {
return d.queue.TakeBlocks() return d.queue.TakeBlocks()
} }
// Has checks if the downloader knows about a particular hash, meaning that its
// either already downloaded of pending retrieval.
func (d *Downloader) Has(hash common.Hash) bool { func (d *Downloader) Has(hash common.Hash) bool {
return d.queue.Has(hash) return d.queue.Has(hash)
} }
@ -604,14 +612,17 @@ func (d *Downloader) banBlocks(peerId string, head common.Hash) error {
// Ban the head hash and phase out any excess // Ban the head hash and phase out any excess
d.banned.Add(blocks[index].Hash()) d.banned.Add(blocks[index].Hash())
for d.banned.Size() > maxBannedHashes { for d.banned.Size() > maxBannedHashes {
var evacuate common.Hash
d.banned.Each(func(item interface{}) bool { d.banned.Each(func(item interface{}) bool {
// Skip any hard coded bans // Skip any hard coded bans
if core.BadHashes[item.(common.Hash)] { if core.BadHashes[item.(common.Hash)] {
return true return true
} }
d.banned.Remove(item) evacuate = item.(common.Hash)
return false return false
}) })
d.banned.Remove(evacuate)
} }
glog.V(logger.Debug).Infof("Banned %d blocks from: %s", index+1, peerId) glog.V(logger.Debug).Infof("Banned %d blocks from: %s", index+1, peerId)
return nil return nil