diff options
author | Péter Szilágyi <peterke@gmail.com> | 2015-06-17 17:03:16 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2015-06-17 17:03:16 +0800 |
commit | 4a1e82cf3f7a5c9d7526fc01aa68466870e2a644 (patch) | |
tree | 9a2ca1a8ad1628cf5b86314d772dc3b92d5dbb19 /eth | |
parent | dfd18d245af37344f8e6fadca55f22a639d7f1ba (diff) | |
download | dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.tar dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.tar.gz dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.tar.bz2 dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.tar.lz dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.tar.xz dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.tar.zst dexon-4a1e82cf3f7a5c9d7526fc01aa68466870e2a644.zip |
eth/downloader: fix #1280, overlapping (good/bad) delivery hang
Diffstat (limited to 'eth')
-rw-r--r-- | eth/downloader/downloader.go | 1 | ||||
-rw-r--r-- | eth/downloader/downloader_test.go | 34 |
2 files changed, 35 insertions, 0 deletions
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 306c4fd2d..c7a05eb35 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -548,6 +548,7 @@ out: peer.Demote() peer.SetIdle() glog.V(logger.Detail).Infof("%s: delivery partially failed: %v", peer, err) + go d.process() } } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index f71c16237..53eb5f81d 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -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. func TestHashAttackerDropping(t *testing.T) { // Define the disconnection requirement for individual hash fetch errors |