diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2015-06-17 18:24:46 +0800 |
---|---|---|
committer | Jeffrey Wilcke <jeffrey@ethereum.org> | 2015-06-17 18:24:46 +0800 |
commit | e4b54f18c6db9f43a4d6cf2916df664bf30c8171 (patch) | |
tree | 04f59a1fb8e7093607393f536e81b5078ac38b82 | |
parent | a3fdef7529e9b58b73d5eb033a2411fafbc9a1f1 (diff) | |
parent | 4a1e82cf3f7a5c9d7526fc01aa68466870e2a644 (diff) | |
download | dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.tar dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.tar.gz dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.tar.bz2 dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.tar.lz dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.tar.xz dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.tar.zst dexon-e4b54f18c6db9f43a4d6cf2916df664bf30c8171.zip |
Merge pull request #1281 from karalabe/fix-overlapping-delivery-hang
eth/downloader: fix #1280, overlapping (good/bad) delivery hang
-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 |