github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/eth/downloader/downloader_test.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package downloader 18 19 import ( 20 "crypto/rand" 21 "errors" 22 "fmt" 23 "math/big" 24 "sync/atomic" 25 "testing" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/event" 33 ) 34 35 var ( 36 testdb, _ = ethdb.NewMemDatabase() 37 genesis = core.GenesisBlockForTesting(testdb, common.Address{}, big.NewInt(0)) 38 ) 39 40 // makeChain creates a chain of n blocks starting at but not including 41 // parent. the returned hash chain is ordered head->parent. 42 func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { 43 blocks := core.GenerateChain(parent, testdb, n, func(i int, gen *core.BlockGen) { 44 gen.SetCoinbase(common.Address{seed}) 45 }) 46 hashes := make([]common.Hash, n+1) 47 hashes[len(hashes)-1] = parent.Hash() 48 blockm := make(map[common.Hash]*types.Block, n+1) 49 blockm[parent.Hash()] = parent 50 for i, b := range blocks { 51 hashes[len(hashes)-i-2] = b.Hash() 52 blockm[b.Hash()] = b 53 } 54 return hashes, blockm 55 } 56 57 // makeChainFork creates two chains of length n, such that h1[:f] and 58 // h2[:f] are different but have a common suffix of length n-f. 59 func makeChainFork(n, f int, parent *types.Block) (h1, h2 []common.Hash, b1, b2 map[common.Hash]*types.Block) { 60 // Create the common suffix. 61 h, b := makeChain(n-f, 0, parent) 62 // Create the forks. 63 h1, b1 = makeChain(f, 1, b[h[0]]) 64 h1 = append(h1, h[1:]...) 65 h2, b2 = makeChain(f, 2, b[h[0]]) 66 h2 = append(h2, h[1:]...) 67 for hash, block := range b { 68 b1[hash] = block 69 b2[hash] = block 70 } 71 return h1, h2, b1, b2 72 } 73 74 // downloadTester is a test simulator for mocking out local block chain. 75 type downloadTester struct { 76 downloader *Downloader 77 78 ownHashes []common.Hash // Hash chain belonging to the tester 79 ownBlocks map[common.Hash]*types.Block // Blocks belonging to the tester 80 peerHashes map[string][]common.Hash // Hash chain belonging to different test peers 81 peerBlocks map[string]map[common.Hash]*types.Block // Blocks belonging to different test peers 82 83 maxHashFetch int // Overrides the maximum number of retrieved hashes 84 } 85 86 // newTester creates a new downloader test mocker. 87 func newTester() *downloadTester { 88 tester := &downloadTester{ 89 ownHashes: []common.Hash{genesis.Hash()}, 90 ownBlocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, 91 peerHashes: make(map[string][]common.Hash), 92 peerBlocks: make(map[string]map[common.Hash]*types.Block), 93 } 94 tester.downloader = New(new(event.TypeMux), tester.hasBlock, tester.getBlock, tester.headBlock, tester.insertChain, tester.dropPeer) 95 96 return tester 97 } 98 99 // sync starts synchronizing with a remote peer, blocking until it completes. 100 func (dl *downloadTester) sync(id string, td *big.Int) error { 101 hash := dl.peerHashes[id][0] 102 103 // If no particular TD was requested, load from the peer's blockchain 104 if td == nil { 105 td = big.NewInt(1) 106 if block, ok := dl.peerBlocks[id][hash]; ok { 107 td = block.Td 108 } 109 } 110 err := dl.downloader.synchronise(id, hash, td) 111 112 for { 113 // If the queue is empty and processing stopped, break 114 hashes, blocks := dl.downloader.queue.Size() 115 if hashes+blocks == 0 && atomic.LoadInt32(&dl.downloader.processing) == 0 { 116 break 117 } 118 // Otherwise sleep a bit and retry 119 time.Sleep(time.Millisecond) 120 } 121 return err 122 } 123 124 // hasBlock checks if a block is pres ent in the testers canonical chain. 125 func (dl *downloadTester) hasBlock(hash common.Hash) bool { 126 return dl.getBlock(hash) != nil 127 } 128 129 // getBlock retrieves a block from the testers canonical chain. 130 func (dl *downloadTester) getBlock(hash common.Hash) *types.Block { 131 return dl.ownBlocks[hash] 132 } 133 134 // headBlock retrieves the current head block from the canonical chain. 135 func (dl *downloadTester) headBlock() *types.Block { 136 return dl.getBlock(dl.ownHashes[len(dl.ownHashes)-1]) 137 } 138 139 // insertChain injects a new batch of blocks into the simulated chain. 140 func (dl *downloadTester) insertChain(blocks types.Blocks) (int, error) { 141 for i, block := range blocks { 142 if _, ok := dl.ownBlocks[block.ParentHash()]; !ok { 143 return i, errors.New("unknown parent") 144 } 145 dl.ownHashes = append(dl.ownHashes, block.Hash()) 146 dl.ownBlocks[block.Hash()] = block 147 } 148 return len(blocks), nil 149 } 150 151 // newPeer registers a new block download source into the downloader. 152 func (dl *downloadTester) newPeer(id string, version int, hashes []common.Hash, blocks map[common.Hash]*types.Block) error { 153 return dl.newSlowPeer(id, version, hashes, blocks, 0) 154 } 155 156 // newSlowPeer registers a new block download source into the downloader, with a 157 // specific delay time on processing the network packets sent to it, simulating 158 // potentially slow network IO. 159 func (dl *downloadTester) newSlowPeer(id string, version int, hashes []common.Hash, blocks map[common.Hash]*types.Block, delay time.Duration) error { 160 err := dl.downloader.RegisterPeer(id, version, hashes[0], dl.peerGetRelHashesFn(id, delay), dl.peerGetAbsHashesFn(id, version, delay), dl.peerGetBlocksFn(id, delay)) 161 if err == nil { 162 // Assign the owned hashes and blocks to the peer (deep copy) 163 dl.peerHashes[id] = make([]common.Hash, len(hashes)) 164 copy(dl.peerHashes[id], hashes) 165 dl.peerBlocks[id] = make(map[common.Hash]*types.Block) 166 for hash, block := range blocks { 167 dl.peerBlocks[id][hash] = block 168 } 169 } 170 return err 171 } 172 173 // dropPeer simulates a hard peer removal from the connection pool. 174 func (dl *downloadTester) dropPeer(id string) { 175 delete(dl.peerHashes, id) 176 delete(dl.peerBlocks, id) 177 178 dl.downloader.UnregisterPeer(id) 179 } 180 181 // peerGetRelHashesFn constructs a GetHashes function associated with a specific 182 // peer in the download tester. The returned function can be used to retrieve 183 // batches of hashes from the particularly requested peer. 184 func (dl *downloadTester) peerGetRelHashesFn(id string, delay time.Duration) func(head common.Hash) error { 185 return func(head common.Hash) error { 186 time.Sleep(delay) 187 188 limit := MaxHashFetch 189 if dl.maxHashFetch > 0 { 190 limit = dl.maxHashFetch 191 } 192 // Gather the next batch of hashes 193 hashes := dl.peerHashes[id] 194 result := make([]common.Hash, 0, limit) 195 for i, hash := range hashes { 196 if hash == head { 197 i++ 198 for len(result) < cap(result) && i < len(hashes) { 199 result = append(result, hashes[i]) 200 i++ 201 } 202 break 203 } 204 } 205 // Delay delivery a bit to allow attacks to unfold 206 go func() { 207 time.Sleep(time.Millisecond) 208 dl.downloader.DeliverHashes(id, result) 209 }() 210 return nil 211 } 212 } 213 214 // peerGetAbsHashesFn constructs a GetHashesFromNumber function associated with 215 // a particular peer in the download tester. The returned function can be used to 216 // retrieve batches of hashes from the particularly requested peer. 217 func (dl *downloadTester) peerGetAbsHashesFn(id string, version int, delay time.Duration) func(uint64, int) error { 218 // If the simulated peer runs eth/60, this message is not supported 219 if version == eth60 { 220 return func(uint64, int) error { return nil } 221 } 222 // Otherwise create a method to request the blocks by number 223 return func(head uint64, count int) error { 224 time.Sleep(delay) 225 226 limit := count 227 if dl.maxHashFetch > 0 { 228 limit = dl.maxHashFetch 229 } 230 // Gather the next batch of hashes 231 hashes := dl.peerHashes[id] 232 result := make([]common.Hash, 0, limit) 233 for i := 0; i < limit && len(hashes)-int(head)-1-i >= 0; i++ { 234 result = append(result, hashes[len(hashes)-int(head)-1-i]) 235 } 236 // Delay delivery a bit to allow attacks to unfold 237 go func() { 238 time.Sleep(time.Millisecond) 239 dl.downloader.DeliverHashes(id, result) 240 }() 241 return nil 242 } 243 } 244 245 // peerGetBlocksFn constructs a getBlocks function associated with a particular 246 // peer in the download tester. The returned function can be used to retrieve 247 // batches of blocks from the particularly requested peer. 248 func (dl *downloadTester) peerGetBlocksFn(id string, delay time.Duration) func([]common.Hash) error { 249 return func(hashes []common.Hash) error { 250 time.Sleep(delay) 251 blocks := dl.peerBlocks[id] 252 result := make([]*types.Block, 0, len(hashes)) 253 for _, hash := range hashes { 254 if block, ok := blocks[hash]; ok { 255 result = append(result, block) 256 } 257 } 258 go dl.downloader.DeliverBlocks(id, result) 259 260 return nil 261 } 262 } 263 264 // Tests that simple synchronization, without throttling from a good peer works. 265 func TestSynchronisation60(t *testing.T) { 266 // Create a small enough block chain to download and the tester 267 targetBlocks := blockCacheLimit - 15 268 hashes, blocks := makeChain(targetBlocks, 0, genesis) 269 270 tester := newTester() 271 tester.newPeer("peer", eth60, hashes, blocks) 272 273 // Synchronise with the peer and make sure all blocks were retrieved 274 if err := tester.sync("peer", nil); err != nil { 275 t.Fatalf("failed to synchronise blocks: %v", err) 276 } 277 if imported := len(tester.ownBlocks); imported != targetBlocks+1 { 278 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1) 279 } 280 } 281 282 // Tests that simple synchronization against a canonical chain works correctly. 283 // In this test common ancestor lookup should be short circuited and not require 284 // binary searching. 285 func TestCanonicalSynchronisation61(t *testing.T) { 286 // Create a small enough block chain to download 287 targetBlocks := blockCacheLimit - 15 288 hashes, blocks := makeChain(targetBlocks, 0, genesis) 289 290 tester := newTester() 291 tester.newPeer("peer", eth61, hashes, blocks) 292 293 // Synchronise with the peer and make sure all blocks were retrieved 294 if err := tester.sync("peer", nil); err != nil { 295 t.Fatalf("failed to synchronise blocks: %v", err) 296 } 297 if imported := len(tester.ownBlocks); imported != targetBlocks+1 { 298 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1) 299 } 300 } 301 302 // Tests that if a large batch of blocks are being downloaded, it is throttled 303 // until the cached blocks are retrieved. 304 func TestThrottling60(t *testing.T) { testThrottling(t, eth60) } 305 func TestThrottling61(t *testing.T) { testThrottling(t, eth61) } 306 307 func testThrottling(t *testing.T, protocol int) { 308 // Create a long block chain to download and the tester 309 targetBlocks := 8 * blockCacheLimit 310 hashes, blocks := makeChain(targetBlocks, 0, genesis) 311 312 tester := newTester() 313 tester.newPeer("peer", protocol, hashes, blocks) 314 315 // Wrap the importer to allow stepping 316 done := make(chan int) 317 tester.downloader.insertChain = func(blocks types.Blocks) (int, error) { 318 n, err := tester.insertChain(blocks) 319 done <- n 320 return n, err 321 } 322 // Start a synchronisation concurrently 323 errc := make(chan error) 324 go func() { 325 errc <- tester.sync("peer", nil) 326 }() 327 // Iteratively take some blocks, always checking the retrieval count 328 for len(tester.ownBlocks) < targetBlocks+1 { 329 // Wait a bit for sync to throttle itself 330 var cached int 331 for start := time.Now(); time.Since(start) < 3*time.Second; { 332 time.Sleep(25 * time.Millisecond) 333 334 cached = len(tester.downloader.queue.blockPool) 335 if cached == blockCacheLimit || len(tester.ownBlocks)+cached == targetBlocks+1 { 336 break 337 } 338 } 339 // Make sure we filled up the cache, then exhaust it 340 time.Sleep(25 * time.Millisecond) // give it a chance to screw up 341 if cached != blockCacheLimit && len(tester.ownBlocks)+cached < targetBlocks+1 { 342 t.Fatalf("block count mismatch: have %v, want %v", cached, blockCacheLimit) 343 } 344 <-done // finish previous blocking import 345 for cached > maxBlockProcess { 346 cached -= <-done 347 } 348 time.Sleep(25 * time.Millisecond) // yield to the insertion 349 } 350 <-done // finish the last blocking import 351 352 // Check that we haven't pulled more blocks than available 353 if len(tester.ownBlocks) > targetBlocks+1 { 354 t.Fatalf("target block count mismatch: have %v, want %v", len(tester.ownBlocks), targetBlocks+1) 355 } 356 if err := <-errc; err != nil { 357 t.Fatalf("block synchronization failed: %v", err) 358 } 359 } 360 361 // Tests that simple synchronization against a forked chain works correctly. In 362 // this test common ancestor lookup should *not* be short circuited, and a full 363 // binary search should be executed. 364 func TestForkedSynchronisation61(t *testing.T) { 365 // Create a long enough forked chain 366 common, fork := MaxHashFetch, 2*MaxHashFetch 367 hashesA, hashesB, blocksA, blocksB := makeChainFork(common+fork, fork, genesis) 368 369 tester := newTester() 370 tester.newPeer("fork A", eth61, hashesA, blocksA) 371 tester.newPeer("fork B", eth61, hashesB, blocksB) 372 373 // Synchronise with the peer and make sure all blocks were retrieved 374 if err := tester.sync("fork A", nil); err != nil { 375 t.Fatalf("failed to synchronise blocks: %v", err) 376 } 377 if imported := len(tester.ownBlocks); imported != common+fork+1 { 378 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, common+fork+1) 379 } 380 // Synchronise with the second peer and make sure that fork is pulled too 381 if err := tester.sync("fork B", nil); err != nil { 382 t.Fatalf("failed to synchronise blocks: %v", err) 383 } 384 if imported := len(tester.ownBlocks); imported != common+2*fork+1 { 385 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, common+2*fork+1) 386 } 387 } 388 389 // Tests that an inactive downloader will not accept incoming hashes and blocks. 390 func TestInactiveDownloader(t *testing.T) { 391 tester := newTester() 392 393 // Check that neither hashes nor blocks are accepted 394 if err := tester.downloader.DeliverHashes("bad peer", []common.Hash{}); err != errNoSyncActive { 395 t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) 396 } 397 if err := tester.downloader.DeliverBlocks("bad peer", []*types.Block{}); err != errNoSyncActive { 398 t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) 399 } 400 } 401 402 // Tests that a canceled download wipes all previously accumulated state. 403 func TestCancel60(t *testing.T) { testCancel(t, eth60) } 404 func TestCancel61(t *testing.T) { testCancel(t, eth61) } 405 406 func testCancel(t *testing.T, protocol int) { 407 // Create a small enough block chain to download and the tester 408 targetBlocks := blockCacheLimit - 15 409 if targetBlocks >= MaxHashFetch { 410 targetBlocks = MaxHashFetch - 15 411 } 412 hashes, blocks := makeChain(targetBlocks, 0, genesis) 413 414 tester := newTester() 415 tester.newPeer("peer", protocol, hashes, blocks) 416 417 // Make sure canceling works with a pristine downloader 418 tester.downloader.cancel() 419 hashCount, blockCount := tester.downloader.queue.Size() 420 if hashCount > 0 || blockCount > 0 { 421 t.Errorf("block or hash count mismatch: %d hashes, %d blocks, want 0", hashCount, blockCount) 422 } 423 // Synchronise with the peer, but cancel afterwards 424 if err := tester.sync("peer", nil); err != nil { 425 t.Fatalf("failed to synchronise blocks: %v", err) 426 } 427 tester.downloader.cancel() 428 hashCount, blockCount = tester.downloader.queue.Size() 429 if hashCount > 0 || blockCount > 0 { 430 t.Errorf("block or hash count mismatch: %d hashes, %d blocks, want 0", hashCount, blockCount) 431 } 432 } 433 434 // Tests that synchronisation from multiple peers works as intended (multi thread sanity test). 435 func TestMultiSynchronisation60(t *testing.T) { testMultiSynchronisation(t, eth60) } 436 func TestMultiSynchronisation61(t *testing.T) { testMultiSynchronisation(t, eth61) } 437 438 func testMultiSynchronisation(t *testing.T, protocol int) { 439 // Create various peers with various parts of the chain 440 targetPeers := 16 441 targetBlocks := targetPeers*blockCacheLimit - 15 442 hashes, blocks := makeChain(targetBlocks, 0, genesis) 443 444 tester := newTester() 445 for i := 0; i < targetPeers; i++ { 446 id := fmt.Sprintf("peer #%d", i) 447 tester.newPeer(id, protocol, hashes[i*blockCacheLimit:], blocks) 448 } 449 // Synchronise with the middle peer and make sure half of the blocks were retrieved 450 id := fmt.Sprintf("peer #%d", targetPeers/2) 451 if err := tester.sync(id, nil); err != nil { 452 t.Fatalf("failed to synchronise blocks: %v", err) 453 } 454 if imported := len(tester.ownBlocks); imported != len(tester.peerHashes[id]) { 455 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, len(tester.peerHashes[id])) 456 } 457 // Synchronise with the best peer and make sure everything is retrieved 458 if err := tester.sync("peer #0", nil); err != nil { 459 t.Fatalf("failed to synchronise blocks: %v", err) 460 } 461 if imported := len(tester.ownBlocks); imported != targetBlocks+1 { 462 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1) 463 } 464 } 465 466 // Tests that synchronising with a peer who's very slow at network IO does not 467 // stall the other peers in the system. 468 func TestSlowSynchronisation60(t *testing.T) { 469 tester := newTester() 470 471 // Create a batch of blocks, with a slow and a full speed peer 472 targetCycles := 2 473 targetBlocks := targetCycles*blockCacheLimit - 15 474 targetIODelay := time.Second 475 hashes, blocks := makeChain(targetBlocks, 0, genesis) 476 477 tester.newSlowPeer("fast", eth60, hashes, blocks, 0) 478 tester.newSlowPeer("slow", eth60, hashes, blocks, targetIODelay) 479 480 // Try to sync with the peers (pull hashes from fast) 481 start := time.Now() 482 if err := tester.sync("fast", nil); err != nil { 483 t.Fatalf("failed to synchronise blocks: %v", err) 484 } 485 if imported := len(tester.ownBlocks); imported != targetBlocks+1 { 486 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1) 487 } 488 // Check that the slow peer got hit at most once per block-cache-size import 489 limit := time.Duration(targetCycles+1) * targetIODelay 490 if delay := time.Since(start); delay >= limit { 491 t.Fatalf("synchronisation exceeded delay limit: have %v, want %v", delay, limit) 492 } 493 } 494 495 // Tests that if a peer returns an invalid chain with a block pointing to a non- 496 // existing parent, it is correctly detected and handled. 497 func TestNonExistingParentAttack60(t *testing.T) { 498 tester := newTester() 499 500 // Forge a single-link chain with a forged header 501 hashes, blocks := makeChain(1, 0, genesis) 502 tester.newPeer("valid", eth60, hashes, blocks) 503 504 wrongblock := types.NewBlock(&types.Header{}, nil, nil, nil) 505 wrongblock.Td = blocks[hashes[0]].Td 506 hashes, blocks = makeChain(1, 0, wrongblock) 507 tester.newPeer("attack", eth60, hashes, blocks) 508 509 // Try and sync with the malicious node and check that it fails 510 if err := tester.sync("attack", nil); err == nil { 511 t.Fatalf("block synchronization succeeded") 512 } 513 if tester.hasBlock(hashes[0]) { 514 t.Fatalf("tester accepted unknown-parent block: %v", blocks[hashes[0]]) 515 } 516 // Try to synchronize with the valid chain and make sure it succeeds 517 if err := tester.sync("valid", nil); err != nil { 518 t.Fatalf("failed to synchronise blocks: %v", err) 519 } 520 if !tester.hasBlock(tester.peerHashes["valid"][0]) { 521 t.Fatalf("tester didn't accept known-parent block: %v", tester.peerBlocks["valid"][hashes[0]]) 522 } 523 } 524 525 // Tests that if a malicious peers keeps sending us repeating hashes, we don't 526 // loop indefinitely. 527 func TestRepeatingHashAttack60(t *testing.T) { // TODO: Is this thing valid?? 528 tester := newTester() 529 530 // Create a valid chain, but drop the last link 531 hashes, blocks := makeChain(blockCacheLimit, 0, genesis) 532 tester.newPeer("valid", eth60, hashes, blocks) 533 tester.newPeer("attack", eth60, hashes[:len(hashes)-1], blocks) 534 535 // Try and sync with the malicious node 536 errc := make(chan error) 537 go func() { 538 errc <- tester.sync("attack", nil) 539 }() 540 // Make sure that syncing returns and does so with a failure 541 select { 542 case <-time.After(time.Second): 543 t.Fatalf("synchronisation blocked") 544 case err := <-errc: 545 if err == nil { 546 t.Fatalf("synchronisation succeeded") 547 } 548 } 549 // Ensure that a valid chain can still pass sync 550 if err := tester.sync("valid", nil); err != nil { 551 t.Fatalf("failed to synchronise blocks: %v", err) 552 } 553 } 554 555 // Tests that if a malicious peers returns a non-existent block hash, it should 556 // eventually time out and the sync reattempted. 557 func TestNonExistingBlockAttack60(t *testing.T) { 558 tester := newTester() 559 560 // Create a valid chain, but forge the last link 561 hashes, blocks := makeChain(blockCacheLimit, 0, genesis) 562 tester.newPeer("valid", eth60, hashes, blocks) 563 564 hashes[len(hashes)/2] = common.Hash{} 565 tester.newPeer("attack", eth60, hashes, blocks) 566 567 // Try and sync with the malicious node and check that it fails 568 if err := tester.sync("attack", nil); err != errPeersUnavailable { 569 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errPeersUnavailable) 570 } 571 // Ensure that a valid chain can still pass sync 572 if err := tester.sync("valid", nil); err != nil { 573 t.Fatalf("failed to synchronise blocks: %v", err) 574 } 575 } 576 577 // Tests that if a malicious peer is returning hashes in a weird order, that the 578 // sync throttler doesn't choke on them waiting for the valid blocks. 579 func TestInvalidHashOrderAttack60(t *testing.T) { 580 tester := newTester() 581 582 // Create a valid long chain, but reverse some hashes within 583 hashes, blocks := makeChain(4*blockCacheLimit, 0, genesis) 584 tester.newPeer("valid", eth60, hashes, blocks) 585 586 chunk1 := make([]common.Hash, blockCacheLimit) 587 chunk2 := make([]common.Hash, blockCacheLimit) 588 copy(chunk1, hashes[blockCacheLimit:2*blockCacheLimit]) 589 copy(chunk2, hashes[2*blockCacheLimit:3*blockCacheLimit]) 590 591 copy(hashes[2*blockCacheLimit:], chunk1) 592 copy(hashes[blockCacheLimit:], chunk2) 593 tester.newPeer("attack", eth60, hashes, blocks) 594 595 // Try and sync with the malicious node and check that it fails 596 if err := tester.sync("attack", nil); err != errInvalidChain { 597 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain) 598 } 599 // Ensure that a valid chain can still pass sync 600 if err := tester.sync("valid", nil); err != nil { 601 t.Fatalf("failed to synchronise blocks: %v", err) 602 } 603 } 604 605 // Tests that if a malicious peer makes up a random hash chain and tries to push 606 // indefinitely, it actually gets caught with it. 607 func TestMadeupHashChainAttack60(t *testing.T) { 608 tester := newTester() 609 blockSoftTTL = 100 * time.Millisecond 610 crossCheckCycle = 25 * time.Millisecond 611 612 // Create a long chain of hashes without backing blocks 613 hashes, blocks := makeChain(4*blockCacheLimit, 0, genesis) 614 615 randomHashes := make([]common.Hash, 1024*blockCacheLimit) 616 for i := range randomHashes { 617 rand.Read(randomHashes[i][:]) 618 } 619 620 tester.newPeer("valid", eth60, hashes, blocks) 621 tester.newPeer("attack", eth60, randomHashes, nil) 622 623 // Try and sync with the malicious node and check that it fails 624 if err := tester.sync("attack", nil); err != errCrossCheckFailed { 625 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errCrossCheckFailed) 626 } 627 // Ensure that a valid chain can still pass sync 628 if err := tester.sync("valid", nil); err != nil { 629 t.Fatalf("failed to synchronise blocks: %v", err) 630 } 631 } 632 633 // Tests that if a malicious peer makes up a random hash chain, and tries to push 634 // indefinitely, one hash at a time, it actually gets caught with it. The reason 635 // this is separate from the classical made up chain attack is that sending hashes 636 // one by one prevents reliable block/parent verification. 637 func TestMadeupHashChainDrippingAttack60(t *testing.T) { 638 // Create a random chain of hashes to drip 639 randomHashes := make([]common.Hash, 16*blockCacheLimit) 640 for i := range randomHashes { 641 rand.Read(randomHashes[i][:]) 642 } 643 randomHashes[len(randomHashes)-1] = genesis.Hash() 644 tester := newTester() 645 646 // Try and sync with the attacker, one hash at a time 647 tester.maxHashFetch = 1 648 tester.newPeer("attack", eth60, randomHashes, nil) 649 if err := tester.sync("attack", nil); err != errStallingPeer { 650 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer) 651 } 652 } 653 654 // Tests that if a malicious peer makes up a random block chain, and tried to 655 // push indefinitely, it actually gets caught with it. 656 func TestMadeupBlockChainAttack60(t *testing.T) { 657 defaultBlockTTL := blockSoftTTL 658 defaultCrossCheckCycle := crossCheckCycle 659 660 blockSoftTTL = 100 * time.Millisecond 661 crossCheckCycle = 25 * time.Millisecond 662 663 // Create a long chain of blocks and simulate an invalid chain by dropping every second 664 hashes, blocks := makeChain(16*blockCacheLimit, 0, genesis) 665 gapped := make([]common.Hash, len(hashes)/2) 666 for i := 0; i < len(gapped); i++ { 667 gapped[i] = hashes[2*i] 668 } 669 // Try and sync with the malicious node and check that it fails 670 tester := newTester() 671 tester.newPeer("attack", eth60, gapped, blocks) 672 if err := tester.sync("attack", nil); err != errCrossCheckFailed { 673 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errCrossCheckFailed) 674 } 675 // Ensure that a valid chain can still pass sync 676 blockSoftTTL = defaultBlockTTL 677 crossCheckCycle = defaultCrossCheckCycle 678 679 tester.newPeer("valid", eth60, hashes, blocks) 680 if err := tester.sync("valid", nil); err != nil { 681 t.Fatalf("failed to synchronise blocks: %v", err) 682 } 683 } 684 685 // Tests that if one/multiple malicious peers try to feed a banned blockchain to 686 // the downloader, it will not keep refetching the same chain indefinitely, but 687 // gradually block pieces of it, until its head is also blocked. 688 func TestBannedChainStarvationAttack60(t *testing.T) { 689 n := 8 * blockCacheLimit 690 fork := n/2 - 23 691 hashes, forkHashes, blocks, forkBlocks := makeChainFork(n, fork, genesis) 692 693 // Create the tester and ban the selected hash. 694 tester := newTester() 695 tester.downloader.banned.Add(forkHashes[fork-1]) 696 tester.newPeer("valid", eth60, hashes, blocks) 697 tester.newPeer("attack", eth60, forkHashes, forkBlocks) 698 699 // Iteratively try to sync, and verify that the banned hash list grows until 700 // the head of the invalid chain is blocked too. 701 for banned := tester.downloader.banned.Size(); ; { 702 // Try to sync with the attacker, check hash chain failure 703 if err := tester.sync("attack", nil); err != errInvalidChain { 704 if tester.downloader.banned.Has(forkHashes[0]) && err == errBannedHead { 705 break 706 } 707 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain) 708 } 709 // Check that the ban list grew with at least 1 new item, or all banned 710 bans := tester.downloader.banned.Size() 711 if bans < banned+1 { 712 t.Fatalf("ban count mismatch: have %v, want %v+", bans, banned+1) 713 } 714 banned = bans 715 } 716 // Check that after banning an entire chain, bad peers get dropped 717 if err := tester.newPeer("new attacker", eth60, forkHashes, forkBlocks); err != errBannedHead { 718 t.Fatalf("peer registration mismatch: have %v, want %v", err, errBannedHead) 719 } 720 if peer := tester.downloader.peers.Peer("new attacker"); peer != nil { 721 t.Fatalf("banned attacker registered: %v", peer) 722 } 723 // Ensure that a valid chain can still pass sync 724 if err := tester.sync("valid", nil); err != nil { 725 t.Fatalf("failed to synchronise blocks: %v", err) 726 } 727 } 728 729 // Tests that if a peer sends excessively many/large invalid chains that are 730 // gradually banned, it will have an upper limit on the consumed memory and also 731 // the origin bad hashes will not be evacuated. 732 func TestBannedChainMemoryExhaustionAttack60(t *testing.T) { 733 // Construct a banned chain with more chunks than the ban limit 734 n := 8 * blockCacheLimit 735 fork := n/2 - 23 736 hashes, forkHashes, blocks, forkBlocks := makeChainFork(n, fork, genesis) 737 738 // Create the tester and ban the root hash of the fork. 739 tester := newTester() 740 tester.downloader.banned.Add(forkHashes[fork-1]) 741 742 // Reduce the test size a bit 743 defaultMaxBlockFetch := MaxBlockFetch 744 defaultMaxBannedHashes := maxBannedHashes 745 746 MaxBlockFetch = 4 747 maxBannedHashes = 256 748 749 tester.newPeer("valid", eth60, hashes, blocks) 750 tester.newPeer("attack", eth60, forkHashes, forkBlocks) 751 752 // Iteratively try to sync, and verify that the banned hash list grows until 753 // the head of the invalid chain is blocked too. 754 for { 755 // Try to sync with the attacker, check hash chain failure 756 if err := tester.sync("attack", nil); err != errInvalidChain { 757 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain) 758 } 759 // Short circuit if the entire chain was banned. 760 if tester.downloader.banned.Has(forkHashes[0]) { 761 break 762 } 763 // Otherwise ensure we never exceed the memory allowance and the hard coded bans are untouched 764 if bans := tester.downloader.banned.Size(); bans > maxBannedHashes { 765 t.Fatalf("ban cap exceeded: have %v, want max %v", bans, maxBannedHashes) 766 } 767 for hash := range core.BadHashes { 768 if !tester.downloader.banned.Has(hash) { 769 t.Fatalf("hard coded ban evacuated: %x", hash) 770 } 771 } 772 } 773 // Ensure that a valid chain can still pass sync 774 MaxBlockFetch = defaultMaxBlockFetch 775 maxBannedHashes = defaultMaxBannedHashes 776 777 if err := tester.sync("valid", nil); err != nil { 778 t.Fatalf("failed to synchronise blocks: %v", err) 779 } 780 } 781 782 // Tests a corner case (potential attack) where a peer delivers both good as well 783 // as unrequested blocks to a hash request. This may trigger a different code 784 // path than the fully correct or fully invalid delivery, potentially causing 785 // internal state problems 786 // 787 // No, don't delete this test, it actually did happen! 788 func TestOverlappingDeliveryAttack60(t *testing.T) { 789 // Create an arbitrary batch of blocks ( < cache-size not to block) 790 targetBlocks := blockCacheLimit - 23 791 hashes, blocks := makeChain(targetBlocks, 0, genesis) 792 793 // Register an attacker that always returns non-requested blocks too 794 tester := newTester() 795 tester.newPeer("attack", eth60, hashes, blocks) 796 797 rawGetBlocks := tester.downloader.peers.Peer("attack").getBlocks 798 tester.downloader.peers.Peer("attack").getBlocks = func(request []common.Hash) error { 799 // Add a non requested hash the screw the delivery (genesis should be fine) 800 return rawGetBlocks(append(request, hashes[0])) 801 } 802 // Test that synchronisation can complete, check for import success 803 if err := tester.sync("attack", nil); err != nil { 804 t.Fatalf("failed to synchronise blocks: %v", err) 805 } 806 start := time.Now() 807 for len(tester.ownHashes) != len(hashes) && time.Since(start) < time.Second { 808 time.Sleep(50 * time.Millisecond) 809 } 810 if len(tester.ownHashes) != len(hashes) { 811 t.Fatalf("chain length mismatch: have %v, want %v", len(tester.ownHashes), len(hashes)) 812 } 813 } 814 815 // Tests that a peer advertising an high TD doesn't get to stall the downloader 816 // afterwards by not sending any useful hashes. 817 func TestHighTDStarvationAttack61(t *testing.T) { 818 tester := newTester() 819 tester.newPeer("attack", eth61, []common.Hash{genesis.Hash()}, nil) 820 if err := tester.sync("attack", big.NewInt(1000000)); err != errStallingPeer { 821 t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer) 822 } 823 } 824 825 // Tests that misbehaving peers are disconnected, whilst behaving ones are not. 826 func TestHashAttackerDropping(t *testing.T) { 827 // Define the disconnection requirement for individual hash fetch errors 828 tests := []struct { 829 result error 830 drop bool 831 }{ 832 {nil, false}, // Sync succeeded, all is well 833 {errBusy, false}, // Sync is already in progress, no problem 834 {errUnknownPeer, false}, // Peer is unknown, was already dropped, don't double drop 835 {errBadPeer, true}, // Peer was deemed bad for some reason, drop it 836 {errStallingPeer, true}, // Peer was detected to be stalling, drop it 837 {errBannedHead, true}, // Peer's head hash is a known bad hash, drop it 838 {errNoPeers, false}, // No peers to download from, soft race, no issue 839 {errPendingQueue, false}, // There are blocks still cached, wait to exhaust, no issue 840 {errTimeout, true}, // No hashes received in due time, drop the peer 841 {errEmptyHashSet, true}, // No hashes were returned as a response, drop as it's a dead end 842 {errPeersUnavailable, true}, // Nobody had the advertised blocks, drop the advertiser 843 {errInvalidChain, true}, // Hash chain was detected as invalid, definitely drop 844 {errCrossCheckFailed, true}, // Hash-origin failed to pass a block cross check, drop 845 {errCancelHashFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop 846 {errCancelBlockFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop 847 } 848 // Run the tests and check disconnection status 849 tester := newTester() 850 for i, tt := range tests { 851 // Register a new peer and ensure it's presence 852 id := fmt.Sprintf("test %d", i) 853 if err := tester.newPeer(id, eth60, []common.Hash{genesis.Hash()}, nil); err != nil { 854 t.Fatalf("test %d: failed to register new peer: %v", i, err) 855 } 856 if _, ok := tester.peerHashes[id]; !ok { 857 t.Fatalf("test %d: registered peer not found", i) 858 } 859 // Simulate a synchronisation and check the required result 860 tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result } 861 862 tester.downloader.Synchronise(id, genesis.Hash(), big.NewInt(1000)) 863 if _, ok := tester.peerHashes[id]; !ok != tt.drop { 864 t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop) 865 } 866 } 867 } 868 869 // Tests that feeding bad blocks will result in a peer drop. 870 func TestBlockAttackerDropping(t *testing.T) { 871 // Define the disconnection requirement for individual block import errors 872 tests := []struct { 873 failure bool 874 drop bool 875 }{ 876 {true, true}, 877 {false, false}, 878 } 879 880 // Run the tests and check disconnection status 881 tester := newTester() 882 for i, tt := range tests { 883 // Register a new peer and ensure it's presence 884 id := fmt.Sprintf("test %d", i) 885 if err := tester.newPeer(id, eth60, []common.Hash{common.Hash{}}, nil); err != nil { 886 t.Fatalf("test %d: failed to register new peer: %v", i, err) 887 } 888 if _, ok := tester.peerHashes[id]; !ok { 889 t.Fatalf("test %d: registered peer not found", i) 890 } 891 // Assemble a good or bad block, depending of the test 892 raw := core.GenerateChain(genesis, testdb, 1, nil)[0] 893 if tt.failure { 894 parent := types.NewBlock(&types.Header{}, nil, nil, nil) 895 raw = core.GenerateChain(parent, testdb, 1, nil)[0] 896 } 897 block := &Block{OriginPeer: id, RawBlock: raw} 898 899 // Simulate block processing and check the result 900 tester.downloader.queue.blockCache[0] = block 901 tester.downloader.process() 902 if _, ok := tester.peerHashes[id]; !ok != tt.drop { 903 t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.failure, !ok, tt.drop) 904 } 905 } 906 }