eth/downloader: assume stale delivery vs. attack

This commit is contained in:
Péter Szilágyi 2015-10-16 13:05:08 +03:00
parent aad2559b53
commit efc1d5127f
3 changed files with 15 additions and 18 deletions

View file

@ -1372,11 +1372,6 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv
// The hash chain is invalid (blocks are not ordered properly), abort
return err
case errInvalidBody, errInvalidReceipt:
// The peer delivered something very bad, drop immediately
glog.V(logger.Error).Infof("%s: delivered invalid %s, dropping", peer, strings.ToLower(kind))
d.dropPeer(peer.id)
case errNoFetchesPending:
// Peer probably timed out with its delivery but came through
// in the end, demote, but allow to to pull from this peer.

View file

@ -1127,6 +1127,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) {
assertOwnChain(t, tester, targetBlocks+1)
}
/*
// Tests that if a peer sends an invalid block piece (body or receipt) for a
// requested block, it gets dropped immediately by the downloader.
func TestInvalidContentAttack62(t *testing.T) { testInvalidContentAttack(t, 62, FullSync) }
@ -1171,7 +1172,7 @@ func testInvalidContentAttack(t *testing.T, protocol int, mode SyncMode) {
if _, ok := tester.peerHashes["receipt attack"]; ok {
t.Fatalf("receipt attacker not detected/dropped")
}
}
}*/
// Tests that a peer advertising an high TD doesn't get to stall the downloader
// afterwards by not sending any useful hashes.

View file

@ -859,7 +859,10 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
}
}
// Assemble each of the results with their headers and retrieved data parts
errs := make([]error, 0)
var (
failure error
useful bool
)
for i, header := range request.Headers {
// Short circuit assembly if no more fetch results are found
if i >= results {
@ -868,15 +871,16 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
// Reconstruct the next result if contents match up
index := int(header.Number.Int64() - int64(q.resultOffset))
if index >= len(q.resultCache) || index < 0 || q.resultCache[index] == nil {
errs = []error{errInvalidChain}
failure = errInvalidChain
break
}
if err := reconstruct(header, i, q.resultCache[index]); err != nil {
errs = []error{err}
failure = err
break
}
donePool[header.Hash()] = struct{}{}
q.resultCache[index].Pending--
useful = true
// Clean up a successful fetch
request.Headers[i] = nil
@ -888,19 +892,16 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
taskQueue.Push(header, -float32(header.Number.Uint64()))
}
}
// If none of the blocks were good, it's a stale delivery
// If none of the data was good, it's a stale delivery
switch {
case len(errs) == 0:
return nil
case failure == nil || failure == errInvalidChain:
return failure
case len(errs) == 1 && (errs[0] == errInvalidChain || errs[0] == errInvalidBody || errs[0] == errInvalidReceipt):
return errs[0]
case len(errs) == results:
return errStaleDelivery
case useful:
return fmt.Errorf("partial failure: %v", failure)
default:
return fmt.Errorf("multiple failures: %v", errs)
return errStaleDelivery
}
}