aboutsummaryrefslogtreecommitdiffstats
path: root/eth
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2015-06-17 17:03:16 +0800
committerPéter Szilágyi <peterke@gmail.com>2015-06-17 17:03:16 +0800
commit4a1e82cf3f7a5c9d7526fc01aa68466870e2a644 (patch)
tree9a2ca1a8ad1628cf5b86314d772dc3b92d5dbb19 /eth
parentdfd18d245af37344f8e6fadca55f22a639d7f1ba (diff)
downloaddexon-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.go1
-rw-r--r--eth/downloader/downloader_test.go34
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