eth/downloader: fix #1280, overlapping (good/bad) delivery hang

This commit is contained in:
Péter Szilágyi 2015-06-17 12:03:16 +03:00
parent dfd18d245a
commit 4a1e82cf3f
2 changed files with 35 additions and 0 deletions

View File

@ -548,6 +548,7 @@ out:
peer.Demote() peer.Demote()
peer.SetIdle() peer.SetIdle()
glog.V(logger.Detail).Infof("%s: delivery partially failed: %v", peer, err) glog.V(logger.Detail).Infof("%s: delivery partially failed: %v", peer, err)
go d.process()
} }
} }

View File

@ -708,6 +708,40 @@ func TestBannedChainMemoryExhaustionAttack(t *testing.T) {
} }
} }
// Tests a corner case (potential attack) where a peer delivers both good as well
// as unrequested blocks to a hash request. This may trigger a different code
// path than the fully correct or fully invalid delivery, potentially causing
// internal state problems
//
// No, don't delete this test, it actually did happen!
func TestOverlappingDeliveryAttack(t *testing.T) {
// Create an arbitrary batch of blocks ( < cache-size not to block)
targetBlocks := blockCacheLimit - 23
hashes := createHashes(targetBlocks, knownHash)
blocks := createBlocksFromHashes(hashes)
// Register an attacker that always returns non-requested blocks too
tester := newTester()
tester.newPeer("attack", hashes, blocks)
rawGetBlocks := tester.downloader.peers.Peer("attack").getBlocks
tester.downloader.peers.Peer("attack").getBlocks = func(request []common.Hash) error {
// Add a non requested hash the screw the delivery (genesis should be fine)
return rawGetBlocks(append(request, hashes[0]))
}
// Test that synchronisation can complete, check for import success
if err := tester.sync("attack"); err != nil {
t.Fatalf("failed to synchronise blocks: %v", err)
}
start := time.Now()
for len(tester.ownHashes) != len(hashes) && time.Since(start) < time.Second {
time.Sleep(50 * time.Millisecond)
}
if len(tester.ownHashes) != len(hashes) {
t.Fatalf("chain length mismatch: have %v, want %v", len(tester.ownHashes), len(hashes))
}
}
// Tests that misbehaving peers are disconnected, whilst behaving ones are not. // Tests that misbehaving peers are disconnected, whilst behaving ones are not.
func TestHashAttackerDropping(t *testing.T) { func TestHashAttackerDropping(t *testing.T) {
// Define the disconnection requirement for individual hash fetch errors // Define the disconnection requirement for individual hash fetch errors