| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | package downloader | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-06-08 14:06:36 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2015-05-15 12:26:34 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/trie" | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-14 15:24:18 +03:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	testKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 	testAddress = crypto.PubkeyToAddress(testKey.PublicKey) | 
					
						
							| 
									
										
										
										
											2015-05-14 15:24:18 +03:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | // Reduce some of the parameters to make the tester faster. | 
					
						
							| 
									
										
										
										
											2016-02-23 12:32:09 +02:00
										 |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 	MaxForkAncestry = uint64(10000) | 
					
						
							| 
									
										
										
										
											2016-02-23 12:32:09 +02:00
										 |  |  | 	blockCacheLimit = 1024 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	fsCriticalTrials = 10 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // downloadTester is a test simulator for mocking out local block chain. | 
					
						
							|  |  |  | type downloadTester struct { | 
					
						
							|  |  |  | 	downloader *Downloader | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	genesis *types.Block   // Genesis blocks used by the tester and peers | 
					
						
							|  |  |  | 	stateDb ethdb.Database // Database used by the tester for syncing from peers | 
					
						
							|  |  |  | 	peerDb  ethdb.Database // Database of the peers containing all data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ownHashes   []common.Hash                  // Hash chain belonging to the tester | 
					
						
							|  |  |  | 	ownHeaders  map[common.Hash]*types.Header  // Headers belonging to the tester | 
					
						
							|  |  |  | 	ownBlocks   map[common.Hash]*types.Block   // Blocks belonging to the tester | 
					
						
							|  |  |  | 	ownReceipts map[common.Hash]types.Receipts // Receipts belonging to the tester | 
					
						
							|  |  |  | 	ownChainTd  map[common.Hash]*big.Int       // Total difficulties of the blocks in the local chain | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	peerHashes   map[string][]common.Hash                  // Hash chain belonging to different test peers | 
					
						
							|  |  |  | 	peerHeaders  map[string]map[common.Hash]*types.Header  // Headers belonging to different test peers | 
					
						
							|  |  |  | 	peerBlocks   map[string]map[common.Hash]*types.Block   // Blocks belonging to different test peers | 
					
						
							|  |  |  | 	peerReceipts map[string]map[common.Hash]types.Receipts // Receipts belonging to different test peers | 
					
						
							|  |  |  | 	peerChainTds map[string]map[common.Hash]*big.Int       // Total difficulties of the blocks in the peer chains | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	peerMissingStates map[string]map[common.Hash]bool // State entries that fast sync should not return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lock sync.RWMutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newTester creates a new downloader test mocker. | 
					
						
							|  |  |  | func newTester() *downloadTester { | 
					
						
							|  |  |  | 	testdb, _ := ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 	genesis := core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester := &downloadTester{ | 
					
						
							|  |  |  | 		genesis:           genesis, | 
					
						
							|  |  |  | 		peerDb:            testdb, | 
					
						
							|  |  |  | 		ownHashes:         []common.Hash{genesis.Hash()}, | 
					
						
							|  |  |  | 		ownHeaders:        map[common.Hash]*types.Header{genesis.Hash(): genesis.Header()}, | 
					
						
							|  |  |  | 		ownBlocks:         map[common.Hash]*types.Block{genesis.Hash(): genesis}, | 
					
						
							|  |  |  | 		ownReceipts:       map[common.Hash]types.Receipts{genesis.Hash(): nil}, | 
					
						
							|  |  |  | 		ownChainTd:        map[common.Hash]*big.Int{genesis.Hash(): genesis.Difficulty()}, | 
					
						
							|  |  |  | 		peerHashes:        make(map[string][]common.Hash), | 
					
						
							|  |  |  | 		peerHeaders:       make(map[string]map[common.Hash]*types.Header), | 
					
						
							|  |  |  | 		peerBlocks:        make(map[string]map[common.Hash]*types.Block), | 
					
						
							|  |  |  | 		peerReceipts:      make(map[string]map[common.Hash]types.Receipts), | 
					
						
							|  |  |  | 		peerChainTds:      make(map[string]map[common.Hash]*big.Int), | 
					
						
							|  |  |  | 		peerMissingStates: make(map[string]map[common.Hash]bool), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tester.stateDb, _ = ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 	tester.stateDb.Put(genesis.Root().Bytes(), []byte{0x00}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 	tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer) | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return tester | 
					
						
							| 
									
										
										
										
											2016-02-23 12:32:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | // makeChain creates a chain of n blocks starting at and including parent. | 
					
						
							|  |  |  | // the returned hash chain is ordered head->parent. In addition, every 3rd block | 
					
						
							|  |  |  | // contains a transaction and every 5th an uncle to allow testing correct block | 
					
						
							|  |  |  | // reassembly. | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	// Generate the block chain | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	blocks, receipts := core.GenerateChain(params.TestChainConfig, parent, dl.peerDb, n, func(i int, block *core.BlockGen) { | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		block.SetCoinbase(common.Address{seed}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 		// If a heavy chain is requested, delay blocks to raise difficulty | 
					
						
							|  |  |  | 		if heavy { | 
					
						
							|  |  |  | 			block.OffsetTime(-1) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		// If the block number is multiple of 3, send a bonus transaction to the miner | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 		if parent == dl.genesis && i%3 == 0 { | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			signer := types.MakeSigner(params.TestChainConfig, block.Number()) | 
					
						
							| 
									
										
										
										
											2017-01-04 20:17:24 +01:00
										 |  |  | 			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				panic(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If the block number is a multiple of 5, add a bonus uncle to the block | 
					
						
							| 
									
										
										
										
											2015-12-17 14:13:30 +01:00
										 |  |  | 		if i > 0 && i%5 == 0 { | 
					
						
							|  |  |  | 			block.AddUncle(&types.Header{ | 
					
						
							|  |  |  | 				ParentHash: block.PrevBlock(i - 1).Hash(), | 
					
						
							|  |  |  | 				Number:     big.NewInt(block.Number().Int64() - 1), | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	// Convert the block-chain into a hash-chain and header/block maps | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 	hashes := make([]common.Hash, n+1) | 
					
						
							|  |  |  | 	hashes[len(hashes)-1] = parent.Hash() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	headerm := make(map[common.Hash]*types.Header, n+1) | 
					
						
							|  |  |  | 	headerm[parent.Hash()] = parent.Header() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 	blockm := make(map[common.Hash]*types.Block, n+1) | 
					
						
							|  |  |  | 	blockm[parent.Hash()] = parent | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	receiptm := make(map[common.Hash]types.Receipts, n+1) | 
					
						
							|  |  |  | 	receiptm[parent.Hash()] = parentReceipts | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 	for i, b := range blocks { | 
					
						
							|  |  |  | 		hashes[len(hashes)-i-2] = b.Hash() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		headerm[b.Hash()] = b.Header() | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 		blockm[b.Hash()] = b | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		receiptm[b.Hash()] = receipts[i] | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	return hashes, headerm, blockm, receiptm | 
					
						
							| 
									
										
										
										
											2015-06-27 02:57:53 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // makeChainFork creates two chains of length n, such that h1[:f] and | 
					
						
							|  |  |  | // h2[:f] are different but have a common suffix of length n-f. | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | func (dl *downloadTester) makeChainFork(n, f int, parent *types.Block, parentReceipts types.Receipts, balanced bool) ([]common.Hash, []common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]*types.Block, map[common.Hash]types.Receipts, map[common.Hash]types.Receipts) { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	// Create the common suffix | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := dl.makeChain(n-f, 0, parent, parentReceipts, false) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 	// Create the forks, making the second heavyer if non balanced forks were requested | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes1, headers1, blocks1, receipts1 := dl.makeChain(f, 1, blocks[hashes[0]], receipts[hashes[0]], false) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	hashes1 = append(hashes1, hashes[1:]...) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 	heavy := false | 
					
						
							|  |  |  | 	if !balanced { | 
					
						
							|  |  |  | 		heavy = true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes2, headers2, blocks2, receipts2 := dl.makeChain(f, 2, blocks[hashes[0]], receipts[hashes[0]], heavy) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	hashes2 = append(hashes2, hashes[1:]...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for hash, header := range headers { | 
					
						
							|  |  |  | 		headers1[hash] = header | 
					
						
							|  |  |  | 		headers2[hash] = header | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for hash, block := range blocks { | 
					
						
							|  |  |  | 		blocks1[hash] = block | 
					
						
							|  |  |  | 		blocks2[hash] = block | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	for hash, receipt := range receipts { | 
					
						
							|  |  |  | 		receipts1[hash] = receipt | 
					
						
							|  |  |  | 		receipts2[hash] = receipt | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return hashes1, hashes2, headers1, headers2, blocks1, blocks2, receipts1, receipts2 | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | // terminate aborts any operations on the embedded downloader and releases all | 
					
						
							|  |  |  | // held resources. | 
					
						
							|  |  |  | func (dl *downloadTester) terminate() { | 
					
						
							|  |  |  | 	dl.downloader.Terminate() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 20:22:40 +03:00
										 |  |  | // sync starts synchronizing with a remote peer, blocking until it completes. | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | func (dl *downloadTester) sync(id string, td *big.Int, mode SyncMode) error { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							| 
									
										
										
										
											2015-07-29 13:20:54 +03:00
										 |  |  | 	hash := dl.peerHashes[id][0] | 
					
						
							|  |  |  | 	// If no particular TD was requested, load from the peer's blockchain | 
					
						
							|  |  |  | 	if td == nil { | 
					
						
							|  |  |  | 		td = big.NewInt(1) | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 		if diff, ok := dl.peerChainTds[id][hash]; ok { | 
					
						
							|  |  |  | 			td = diff | 
					
						
							| 
									
										
										
										
											2015-07-29 13:20:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.RUnlock() | 
					
						
							| 
									
										
										
										
											2016-05-30 12:01:50 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the chosen peer and ensure proper cleanup afterwards | 
					
						
							|  |  |  | 	err := dl.downloader.synchronise(id, hash, td, mode) | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-dl.downloader.cancelCh: | 
					
						
							|  |  |  | 		// Ok, downloader fully cancelled after sync cycle | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// Downloader is still accepting packets, can block a peer up | 
					
						
							|  |  |  | 		panic("downloader active post sync cycle") // panic will be caught by tester | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2015-05-03 16:09:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // HasHeader checks if a header is present in the testers canonical chain. | 
					
						
							| 
									
										
										
										
											2017-09-09 18:03:07 +02:00
										 |  |  | func (dl *downloadTester) HasHeader(hash common.Hash, number uint64) bool { | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 	return dl.GetHeaderByHash(hash) != nil | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // HasBlockAndState checks if a block and associated state is present in the testers canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) HasBlockAndState(hash common.Hash) bool { | 
					
						
							|  |  |  | 	block := dl.GetBlockByHash(hash) | 
					
						
							| 
									
										
										
										
											2015-12-29 14:01:08 +02:00
										 |  |  | 	if block == nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, err := dl.stateDb.Get(block.Root().Bytes()) | 
					
						
							|  |  |  | 	return err == nil | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // GetHeader retrieves a header from the testers canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) GetHeaderByHash(hash common.Hash) *types.Header { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	return dl.ownHeaders[hash] | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // GetBlock retrieves a block from the testers canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) GetBlockByHash(hash common.Hash) *types.Block { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 17:14:45 +03:00
										 |  |  | 	return dl.ownBlocks[hash] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // CurrentHeader retrieves the current head header from the canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) CurrentHeader() *types.Header { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	for i := len(dl.ownHashes) - 1; i >= 0; i-- { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if header := dl.ownHeaders[dl.ownHashes[i]]; header != nil { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 			return header | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	return dl.genesis.Header() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // CurrentBlock retrieves the current head block from the canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) CurrentBlock() *types.Block { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	for i := len(dl.ownHashes) - 1; i >= 0; i-- { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if block := dl.ownBlocks[dl.ownHashes[i]]; block != nil { | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 			if _, err := dl.stateDb.Get(block.Root().Bytes()); err == nil { | 
					
						
							|  |  |  | 				return block | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	return dl.genesis | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // CurrentFastBlock retrieves the current head fast-sync block from the canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) CurrentFastBlock() *types.Block { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := len(dl.ownHashes) - 1; i >= 0; i-- { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if block := dl.ownBlocks[dl.ownHashes[i]]; block != nil { | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 			return block | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	return dl.genesis | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-03 15:17:12 +01:00
										 |  |  | // FastSyncCommitHead manually sets the head block to a given hash. | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error { | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	// For now only check that the state trie is correct | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 	if block := dl.GetBlockByHash(hash); block != nil { | 
					
						
							| 
									
										
										
										
											2016-10-14 18:04:33 +02:00
										 |  |  | 		_, err := trie.NewSecure(block.Root(), dl.stateDb, 0) | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fmt.Errorf("non existent block: %x", hash[:4]) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // GetTdByHash retrieves the block's total difficulty from the canonical chain. | 
					
						
							|  |  |  | func (dl *downloadTester) GetTdByHash(hash common.Hash) *big.Int { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 	return dl.ownChainTd[hash] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // InsertHeaderChain injects a new batch of headers into the simulated chain. | 
					
						
							|  |  |  | func (dl *downloadTester) InsertHeaderChain(headers []*types.Header, checkFreq int) (int, error) { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	dl.lock.Lock() | 
					
						
							|  |  |  | 	defer dl.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 11:27:49 -07:00
										 |  |  | 	// Do a quick check, as the blockchain.InsertHeaderChain doesn't insert anything in case of errors | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	if _, ok := dl.ownHeaders[headers[0].ParentHash]; !ok { | 
					
						
							|  |  |  | 		return 0, errors.New("unknown parent") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 1; i < len(headers); i++ { | 
					
						
							|  |  |  | 		if headers[i].ParentHash != headers[i-1].Hash() { | 
					
						
							|  |  |  | 			return i, errors.New("unknown parent") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Do a full insert if pre-checks passed | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	for i, header := range headers { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		if _, ok := dl.ownHeaders[header.Hash()]; ok { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		if _, ok := dl.ownHeaders[header.ParentHash]; !ok { | 
					
						
							|  |  |  | 			return i, errors.New("unknown parent") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dl.ownHashes = append(dl.ownHashes, header.Hash()) | 
					
						
							|  |  |  | 		dl.ownHeaders[header.Hash()] = header | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		dl.ownChainTd[header.Hash()] = new(big.Int).Add(dl.ownChainTd[header.ParentHash], header.Difficulty) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return len(headers), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // InsertChain injects a new batch of blocks into the simulated chain. | 
					
						
							|  |  |  | func (dl *downloadTester) InsertChain(blocks types.Blocks) (int, error) { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.Lock() | 
					
						
							|  |  |  | 	defer dl.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	for i, block := range blocks { | 
					
						
							| 
									
										
										
										
											2015-12-29 14:01:08 +02:00
										 |  |  | 		if parent, ok := dl.ownBlocks[block.ParentHash()]; !ok { | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 			return i, errors.New("unknown parent") | 
					
						
							| 
									
										
										
										
											2015-12-29 14:01:08 +02:00
										 |  |  | 		} else if _, err := dl.stateDb.Get(parent.Root().Bytes()); err != nil { | 
					
						
							|  |  |  | 			return i, fmt.Errorf("unknown parent state %x: %v", parent.Root(), err) | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if _, ok := dl.ownHeaders[block.Hash()]; !ok { | 
					
						
							|  |  |  | 			dl.ownHashes = append(dl.ownHashes, block.Hash()) | 
					
						
							|  |  |  | 			dl.ownHeaders[block.Hash()] = block.Header() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 		dl.ownBlocks[block.Hash()] = block | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		dl.stateDb.Put(block.Root().Bytes(), []byte{0x00}) | 
					
						
							|  |  |  | 		dl.ownChainTd[block.Hash()] = new(big.Int).Add(dl.ownChainTd[block.ParentHash()], block.Difficulty()) | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return len(blocks), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // InsertReceiptChain injects a new batch of receipts into the simulated chain. | 
					
						
							|  |  |  | func (dl *downloadTester) InsertReceiptChain(blocks types.Blocks, receipts []types.Receipts) (int, error) { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	dl.lock.Lock() | 
					
						
							|  |  |  | 	defer dl.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < len(blocks) && i < len(receipts); i++ { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		if _, ok := dl.ownHeaders[blocks[i].Hash()]; !ok { | 
					
						
							|  |  |  | 			return i, errors.New("unknown owner") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		if _, ok := dl.ownBlocks[blocks[i].ParentHash()]; !ok { | 
					
						
							|  |  |  | 			return i, errors.New("unknown parent") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dl.ownBlocks[blocks[i].Hash()] = blocks[i] | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		dl.ownReceipts[blocks[i].Hash()] = receipts[i] | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return len(blocks), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | // Rollback removes some recently added elements from the chain. | 
					
						
							|  |  |  | func (dl *downloadTester) Rollback(hashes []common.Hash) { | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	dl.lock.Lock() | 
					
						
							|  |  |  | 	defer dl.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := len(hashes) - 1; i >= 0; i-- { | 
					
						
							|  |  |  | 		if dl.ownHashes[len(dl.ownHashes)-1] == hashes[i] { | 
					
						
							|  |  |  | 			dl.ownHashes = dl.ownHashes[:len(dl.ownHashes)-1] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		delete(dl.ownChainTd, hashes[i]) | 
					
						
							|  |  |  | 		delete(dl.ownHeaders, hashes[i]) | 
					
						
							|  |  |  | 		delete(dl.ownReceipts, hashes[i]) | 
					
						
							|  |  |  | 		delete(dl.ownBlocks, hashes[i]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 17:14:45 +03:00
										 |  |  | // newPeer registers a new block download source into the downloader. | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | func (dl *downloadTester) newPeer(id string, version int, hashes []common.Hash, headers map[common.Hash]*types.Header, blocks map[common.Hash]*types.Block, receipts map[common.Hash]types.Receipts) error { | 
					
						
							|  |  |  | 	return dl.newSlowPeer(id, version, hashes, headers, blocks, receipts, 0) | 
					
						
							| 
									
										
										
										
											2015-06-15 12:26:05 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newSlowPeer registers a new block download source into the downloader, with a | 
					
						
							|  |  |  | // specific delay time on processing the network packets sent to it, simulating | 
					
						
							|  |  |  | // potentially slow network IO. | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | func (dl *downloadTester) newSlowPeer(id string, version int, hashes []common.Hash, headers map[common.Hash]*types.Header, blocks map[common.Hash]*types.Block, receipts map[common.Hash]types.Receipts, delay time.Duration) error { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.Lock() | 
					
						
							|  |  |  | 	defer dl.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	var err = dl.downloader.RegisterPeer(id, version, &downloadTesterPeer{dl: dl, id: id, delay: delay}) | 
					
						
							| 
									
										
										
										
											2015-06-11 17:14:45 +03:00
										 |  |  | 	if err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		// Assign the owned hashes, headers and blocks to the peer (deep copy) | 
					
						
							| 
									
										
										
										
											2015-06-11 20:22:40 +03:00
										 |  |  | 		dl.peerHashes[id] = make([]common.Hash, len(hashes)) | 
					
						
							|  |  |  | 		copy(dl.peerHashes[id], hashes) | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		dl.peerHeaders[id] = make(map[common.Hash]*types.Header) | 
					
						
							| 
									
										
										
										
											2015-06-11 20:22:40 +03:00
										 |  |  | 		dl.peerBlocks[id] = make(map[common.Hash]*types.Block) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		dl.peerReceipts[id] = make(map[common.Hash]types.Receipts) | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 		dl.peerChainTds[id] = make(map[common.Hash]*big.Int) | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 		dl.peerMissingStates[id] = make(map[common.Hash]bool) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		genesis := hashes[len(hashes)-1] | 
					
						
							|  |  |  | 		if header := headers[genesis]; header != nil { | 
					
						
							|  |  |  | 			dl.peerHeaders[id][genesis] = header | 
					
						
							|  |  |  | 			dl.peerChainTds[id][genesis] = header.Difficulty | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if block := blocks[genesis]; block != nil { | 
					
						
							|  |  |  | 			dl.peerBlocks[id][genesis] = block | 
					
						
							|  |  |  | 			dl.peerChainTds[id][genesis] = block.Difficulty() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for i := len(hashes) - 2; i >= 0; i-- { | 
					
						
							|  |  |  | 			hash := hashes[i] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 			if header, ok := headers[hash]; ok { | 
					
						
							|  |  |  | 				dl.peerHeaders[id][hash] = header | 
					
						
							|  |  |  | 				if _, ok := dl.peerHeaders[id][header.ParentHash]; ok { | 
					
						
							|  |  |  | 					dl.peerChainTds[id][hash] = new(big.Int).Add(header.Difficulty, dl.peerChainTds[id][header.ParentHash]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 			if block, ok := blocks[hash]; ok { | 
					
						
							|  |  |  | 				dl.peerBlocks[id][hash] = block | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 				if _, ok := dl.peerBlocks[id][block.ParentHash()]; ok { | 
					
						
							|  |  |  | 					dl.peerChainTds[id][hash] = new(big.Int).Add(block.Difficulty(), dl.peerChainTds[id][block.ParentHash()]) | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 			if receipt, ok := receipts[hash]; ok { | 
					
						
							|  |  |  | 				dl.peerReceipts[id][hash] = receipt | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-11 20:22:40 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-11 17:14:45 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | // dropPeer simulates a hard peer removal from the connection pool. | 
					
						
							|  |  |  | func (dl *downloadTester) dropPeer(id string) { | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	dl.lock.Lock() | 
					
						
							|  |  |  | 	defer dl.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 	delete(dl.peerHashes, id) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	delete(dl.peerHeaders, id) | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 	delete(dl.peerBlocks, id) | 
					
						
							| 
									
										
										
										
											2015-09-07 20:43:01 +03:00
										 |  |  | 	delete(dl.peerChainTds, id) | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dl.downloader.UnregisterPeer(id) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | type downloadTesterPeer struct { | 
					
						
							|  |  |  | 	dl    *downloadTester | 
					
						
							|  |  |  | 	id    string | 
					
						
							|  |  |  | 	delay time.Duration | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	lock  sync.RWMutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // setDelay is a thread safe setter for the network delay value. | 
					
						
							|  |  |  | func (dlp *downloadTesterPeer) setDelay(delay time.Duration) { | 
					
						
							|  |  |  | 	dlp.lock.Lock() | 
					
						
							|  |  |  | 	defer dlp.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dlp.delay = delay | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // waitDelay is a thread safe way to sleep for the configured time. | 
					
						
							|  |  |  | func (dlp *downloadTesterPeer) waitDelay() { | 
					
						
							|  |  |  | 	dlp.lock.RLock() | 
					
						
							|  |  |  | 	delay := dlp.delay | 
					
						
							|  |  |  | 	dlp.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	time.Sleep(delay) | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Head constructs a function to retrieve a peer's current head hash | 
					
						
							| 
									
										
										
										
											2016-07-25 15:14:14 +03:00
										 |  |  | // and total difficulty. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | func (dlp *downloadTesterPeer) Head() (common.Hash, *big.Int) { | 
					
						
							|  |  |  | 	dlp.dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dlp.dl.lock.RUnlock() | 
					
						
							| 
									
										
										
										
											2016-07-25 15:14:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	return dlp.dl.peerHashes[dlp.id][0], nil | 
					
						
							| 
									
										
										
										
											2016-07-25 15:14:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | // RequestHeadersByHash constructs a GetBlockHeaders function based on a hashed | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | // origin; associated with a particular peer in the download tester. The returned | 
					
						
							|  |  |  | // function can be used to retrieve batches of headers from the particular peer. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | func (dlp *downloadTesterPeer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { | 
					
						
							|  |  |  | 	// Find the canonical number of the hash | 
					
						
							|  |  |  | 	dlp.dl.lock.RLock() | 
					
						
							|  |  |  | 	number := uint64(0) | 
					
						
							|  |  |  | 	for num, hash := range dlp.dl.peerHashes[dlp.id] { | 
					
						
							|  |  |  | 		if hash == origin { | 
					
						
							|  |  |  | 			number = uint64(len(dlp.dl.peerHashes[dlp.id]) - num - 1) | 
					
						
							|  |  |  | 			break | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	dlp.dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Use the absolute header fetcher to satisfy the query | 
					
						
							|  |  |  | 	return dlp.RequestHeadersByNumber(number, amount, skip, reverse) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | // RequestHeadersByNumber constructs a GetBlockHeaders function based on a numbered | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | // origin; associated with a particular peer in the download tester. The returned | 
					
						
							|  |  |  | // function can be used to retrieve batches of headers from the particular peer. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	dlp.waitDelay() | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dlp.dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dlp.dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Gather the next batch of headers | 
					
						
							|  |  |  | 	hashes := dlp.dl.peerHashes[dlp.id] | 
					
						
							|  |  |  | 	headers := dlp.dl.peerHeaders[dlp.id] | 
					
						
							|  |  |  | 	result := make([]*types.Header, 0, amount) | 
					
						
							|  |  |  | 	for i := 0; i < amount && len(hashes)-int(origin)-1-i*(skip+1) >= 0; i++ { | 
					
						
							|  |  |  | 		if header, ok := headers[hashes[len(hashes)-int(origin)-1-i*(skip+1)]]; ok { | 
					
						
							|  |  |  | 			result = append(result, header) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	// Delay delivery a bit to allow attacks to unfold | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		time.Sleep(time.Millisecond) | 
					
						
							|  |  |  | 		dlp.dl.downloader.DeliverHeaders(dlp.id, result) | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | // RequestBodies constructs a getBlockBodies method associated with a particular | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | // peer in the download tester. The returned function can be used to retrieve | 
					
						
							|  |  |  | // batches of block bodies from the particularly requested peer. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash) error { | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	dlp.waitDelay() | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	dlp.dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dlp.dl.lock.RUnlock() | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	blocks := dlp.dl.peerBlocks[dlp.id] | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	transactions := make([][]*types.Transaction, 0, len(hashes)) | 
					
						
							|  |  |  | 	uncles := make([][]*types.Header, 0, len(hashes)) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	for _, hash := range hashes { | 
					
						
							|  |  |  | 		if block, ok := blocks[hash]; ok { | 
					
						
							|  |  |  | 			transactions = append(transactions, block.Transactions()) | 
					
						
							|  |  |  | 			uncles = append(uncles, block.Uncles()) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	go dlp.dl.downloader.DeliverBodies(dlp.id, transactions, uncles) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-04-12 12:38:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | // RequestReceipts constructs a getReceipts method associated with a particular | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | // peer in the download tester. The returned function can be used to retrieve | 
					
						
							|  |  |  | // batches of block receipts from the particularly requested peer. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | func (dlp *downloadTesterPeer) RequestReceipts(hashes []common.Hash) error { | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	dlp.waitDelay() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	dlp.dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dlp.dl.lock.RUnlock() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	receipts := dlp.dl.peerReceipts[dlp.id] | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	results := make([][]*types.Receipt, 0, len(hashes)) | 
					
						
							|  |  |  | 	for _, hash := range hashes { | 
					
						
							|  |  |  | 		if receipt, ok := receipts[hash]; ok { | 
					
						
							|  |  |  | 			results = append(results, receipt) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	go dlp.dl.downloader.DeliverReceipts(dlp.id, results) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | // RequestNodeData constructs a getNodeData method associated with a particular | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | // peer in the download tester. The returned function can be used to retrieve | 
					
						
							|  |  |  | // batches of node state data from the particularly requested peer. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | func (dlp *downloadTesterPeer) RequestNodeData(hashes []common.Hash) error { | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	dlp.waitDelay() | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dlp.dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dlp.dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	results := make([][]byte, 0, len(hashes)) | 
					
						
							|  |  |  | 	for _, hash := range hashes { | 
					
						
							|  |  |  | 		if data, err := dlp.dl.peerDb.Get(hash.Bytes()); err == nil { | 
					
						
							|  |  |  | 			if !dlp.dl.peerMissingStates[dlp.id][hash] { | 
					
						
							|  |  |  | 				results = append(results, data) | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 	go dlp.dl.downloader.DeliverNodeData(dlp.id, results) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | // assertOwnChain checks if the local chain contains the correct number of items | 
					
						
							|  |  |  | // of the various chain components. | 
					
						
							|  |  |  | func assertOwnChain(t *testing.T, tester *downloadTester, length int) { | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	assertOwnForkedChain(t, tester, 1, []int{length}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // assertOwnForkedChain checks if the local forked chain contains the correct | 
					
						
							|  |  |  | // number of items of the various chain components. | 
					
						
							|  |  |  | func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, lengths []int) { | 
					
						
							|  |  |  | 	// Initialize the counters for the first fork | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	headers, blocks := lengths[0], lengths[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	minReceipts, maxReceipts := lengths[0]-fsMinFullBlocks-fsPivotInterval, lengths[0]-fsMinFullBlocks | 
					
						
							|  |  |  | 	if minReceipts < 0 { | 
					
						
							|  |  |  | 		minReceipts = 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if maxReceipts < 0 { | 
					
						
							|  |  |  | 		maxReceipts = 1 | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Update the counters for each subsequent fork | 
					
						
							|  |  |  | 	for _, length := range lengths[1:] { | 
					
						
							|  |  |  | 		headers += length - common | 
					
						
							|  |  |  | 		blocks += length - common | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		minReceipts += length - common - fsMinFullBlocks - fsPivotInterval | 
					
						
							|  |  |  | 		maxReceipts += length - common - fsMinFullBlocks | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	switch tester.downloader.mode { | 
					
						
							|  |  |  | 	case FullSync: | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		minReceipts, maxReceipts = 1, 1 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	case LightSync: | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		blocks, minReceipts, maxReceipts = 1, 1, 1 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if hs := len(tester.ownHeaders); hs != headers { | 
					
						
							|  |  |  | 		t.Fatalf("synchronised headers mismatch: have %v, want %v", hs, headers) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if bs := len(tester.ownBlocks); bs != blocks { | 
					
						
							|  |  |  | 		t.Fatalf("synchronised blocks mismatch: have %v, want %v", bs, blocks) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if rs := len(tester.ownReceipts); rs < minReceipts || rs > maxReceipts { | 
					
						
							|  |  |  | 		t.Fatalf("synchronised receipts mismatch: have %v, want between [%v, %v]", rs, minReceipts, maxReceipts) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	// Verify the state trie too for fast syncs | 
					
						
							|  |  |  | 	if tester.downloader.mode == FastSync { | 
					
						
							| 
									
										
										
										
											2017-01-09 11:16:06 +01:00
										 |  |  | 		var index int | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if pivot := int(tester.downloader.queue.fastSyncPivot); pivot < common { | 
					
						
							|  |  |  | 			index = pivot | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			index = len(tester.ownHashes) - lengths[len(lengths)-1] + int(tester.downloader.queue.fastSyncPivot) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if index > 0 { | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 			if statedb, err := state.New(tester.ownHeaders[tester.ownHashes[index]].Root, state.NewDatabase(tester.stateDb)); statedb == nil || err != nil { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 				t.Fatalf("state reconstruction failed: %v", err) | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | // Tests that simple synchronization against a canonical chain works correctly. | 
					
						
							|  |  |  | // In this test common ancestor lookup should be short circuited and not require | 
					
						
							|  |  |  | // binary searching. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestCanonicalSynchronisation62(t *testing.T)      { testCanonicalSynchronisation(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestCanonicalSynchronisation63Full(t *testing.T)  { testCanonicalSynchronisation(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestCanonicalSynchronisation63Fast(t *testing.T)  { testCanonicalSynchronisation(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestCanonicalSynchronisation64Full(t *testing.T)  { testCanonicalSynchronisation(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestCanonicalSynchronisation64Fast(t *testing.T)  { testCanonicalSynchronisation(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestCanonicalSynchronisation64Light(t *testing.T) { testCanonicalSynchronisation(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testCanonicalSynchronisation(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							|  |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-05-10 00:34:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	// Synchronise with the peer and make sure all relevant data was retrieved | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("peer", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							| 
									
										
										
										
											2015-05-29 19:47:00 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							| 
									
										
										
										
											2015-05-10 00:34:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | // Tests that if a large batch of blocks are being downloaded, it is throttled | 
					
						
							|  |  |  | // until the cached blocks are retrieved. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestThrottling62(t *testing.T)     { testThrottling(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestThrottling63Full(t *testing.T) { testThrottling(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestThrottling63Fast(t *testing.T) { testThrottling(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestThrottling64Full(t *testing.T) { testThrottling(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestThrottling64Fast(t *testing.T) { testThrottling(t, 64, FastSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testThrottling(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a long block chain to download and the tester | 
					
						
							|  |  |  | 	targetBlocks := 8 * blockCacheLimit | 
					
						
							|  |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-05-07 14:40:50 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	// Wrap the importer to allow stepping | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	blocked, proceed := uint32(0), make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	tester.downloader.chainInsertHook = func(results []*fetchResult) { | 
					
						
							|  |  |  | 		atomic.StoreUint32(&blocked, uint32(len(results))) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		<-proceed | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-29 19:47:00 +03:00
										 |  |  | 	// Start a synchronisation concurrently | 
					
						
							|  |  |  | 	errc := make(chan error) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		errc <- tester.sync("peer", nil, mode) | 
					
						
							| 
									
										
										
										
											2015-05-29 19:47:00 +03:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 	// Iteratively take some blocks, always checking the retrieval count | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		// Check the retrieval count synchronously (! reason for this ugly block) | 
					
						
							|  |  |  | 		tester.lock.RLock() | 
					
						
							|  |  |  | 		retrieved := len(tester.ownBlocks) | 
					
						
							|  |  |  | 		tester.lock.RUnlock() | 
					
						
							|  |  |  | 		if retrieved >= targetBlocks+1 { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 		// Wait a bit for sync to throttle itself | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		var cached, frozen int | 
					
						
							| 
									
										
										
										
											2015-12-30 14:06:09 +02:00
										 |  |  | 		for start := time.Now(); time.Since(start) < 3*time.Second; { | 
					
						
							| 
									
										
										
										
											2015-06-07 18:46:32 +03:00
										 |  |  | 			time.Sleep(25 * time.Millisecond) | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 			tester.lock.Lock() | 
					
						
							|  |  |  | 			tester.downloader.queue.lock.Lock() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 			cached = len(tester.downloader.queue.blockDonePool) | 
					
						
							|  |  |  | 			if mode == FastSync { | 
					
						
							|  |  |  | 				if receipts := len(tester.downloader.queue.receiptDonePool); receipts < cached { | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 					if tester.downloader.queue.resultCache[receipts].Header.Number.Uint64() < tester.downloader.queue.fastSyncPivot { | 
					
						
							|  |  |  | 						cached = receipts | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 			frozen = int(atomic.LoadUint32(&blocked)) | 
					
						
							|  |  |  | 			retrieved = len(tester.ownBlocks) | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 			tester.downloader.queue.lock.Unlock() | 
					
						
							|  |  |  | 			tester.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 			if cached == blockCacheLimit || retrieved+cached+frozen == targetBlocks+1 { | 
					
						
							| 
									
										
										
										
											2015-06-07 18:46:32 +03:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 		// Make sure we filled up the cache, then exhaust it | 
					
						
							|  |  |  | 		time.Sleep(25 * time.Millisecond) // give it a chance to screw up | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		tester.lock.RLock() | 
					
						
							|  |  |  | 		retrieved = len(tester.ownBlocks) | 
					
						
							|  |  |  | 		tester.lock.RUnlock() | 
					
						
							|  |  |  | 		if cached != blockCacheLimit && retrieved+cached+frozen != targetBlocks+1 { | 
					
						
							|  |  |  | 			t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheLimit, retrieved, frozen, targetBlocks+1) | 
					
						
							| 
									
										
										
										
											2015-05-29 19:47:00 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		// Permit the blocked blocks to import | 
					
						
							|  |  |  | 		if atomic.LoadUint32(&blocked) > 0 { | 
					
						
							|  |  |  | 			atomic.StoreUint32(&blocked, uint32(0)) | 
					
						
							|  |  |  | 			proceed <- struct{}{} | 
					
						
							| 
									
										
										
										
											2015-05-29 19:47:00 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Check that we haven't pulled more blocks than available | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							| 
									
										
										
										
											2015-05-29 19:47:00 +03:00
										 |  |  | 	if err := <-errc; err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block synchronization failed: %v", err) | 
					
						
							| 
									
										
										
										
											2015-05-07 14:40:50 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-14 15:24:18 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | // Tests that simple synchronization against a forked chain works correctly. In | 
					
						
							|  |  |  | // this test common ancestor lookup should *not* be short circuited, and a full | 
					
						
							|  |  |  | // binary search should be executed. | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | func TestForkedSync62(t *testing.T)      { testForkedSync(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestForkedSync63Full(t *testing.T)  { testForkedSync(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestForkedSync63Fast(t *testing.T)  { testForkedSync(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestForkedSync64Full(t *testing.T)  { testForkedSync(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestForkedSync64Fast(t *testing.T)  { testForkedSync(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestForkedSync64Light(t *testing.T) { testForkedSync(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testForkedSync(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a long enough forked chain | 
					
						
							|  |  |  | 	common, fork := MaxHashFetch, 2*MaxHashFetch | 
					
						
							|  |  |  | 	hashesA, hashesB, headersA, headersB, blocksA, blocksB, receiptsA, receiptsB := tester.makeChainFork(common+fork, fork, tester.genesis, nil, true) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("fork A", protocol, hashesA, headersA, blocksA, receiptsA) | 
					
						
							|  |  |  | 	tester.newPeer("fork B", protocol, hashesB, headersB, blocksB, receiptsB) | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the peer and make sure all blocks were retrieved | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("fork A", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, common+fork+1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 	// Synchronise with the second peer and make sure that fork is pulled too | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("fork B", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	assertOwnForkedChain(t, tester, common+1, []int{common + fork + 1, common + fork + 1}) | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | // Tests that synchronising against a much shorter but much heavyer fork works | 
					
						
							|  |  |  | // corrently and is not dropped. | 
					
						
							|  |  |  | func TestHeavyForkedSync62(t *testing.T)      { testHeavyForkedSync(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestHeavyForkedSync63Full(t *testing.T)  { testHeavyForkedSync(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestHeavyForkedSync63Fast(t *testing.T)  { testHeavyForkedSync(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestHeavyForkedSync64Full(t *testing.T)  { testHeavyForkedSync(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestHeavyForkedSync64Fast(t *testing.T)  { testHeavyForkedSync(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestHeavyForkedSync64Light(t *testing.T) { testHeavyForkedSync(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testHeavyForkedSync(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							|  |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a long enough forked chain | 
					
						
							|  |  |  | 	common, fork := MaxHashFetch, 4*MaxHashFetch | 
					
						
							|  |  |  | 	hashesA, hashesB, headersA, headersB, blocksA, blocksB, receiptsA, receiptsB := tester.makeChainFork(common+fork, fork, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 	tester.newPeer("light", protocol, hashesA, headersA, blocksA, receiptsA) | 
					
						
							|  |  |  | 	tester.newPeer("heavy", protocol, hashesB[fork/2:], headersB, blocksB, receiptsB) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the peer and make sure all blocks were retrieved | 
					
						
							|  |  |  | 	if err := tester.sync("light", nil, mode); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assertOwnChain(t, tester, common+fork+1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the second peer and make sure that fork is pulled too | 
					
						
							|  |  |  | 	if err := tester.sync("heavy", nil, mode); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assertOwnForkedChain(t, tester, common+1, []int{common + fork + 1, common + fork/2 + 1}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that chain forks are contained within a certain interval of the current | 
					
						
							|  |  |  | // chain head, ensuring that malicious peers cannot waste resources by feeding | 
					
						
							|  |  |  | // long dead chains. | 
					
						
							|  |  |  | func TestBoundedForkedSync62(t *testing.T)      { testBoundedForkedSync(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestBoundedForkedSync63Full(t *testing.T)  { testBoundedForkedSync(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestBoundedForkedSync63Fast(t *testing.T)  { testBoundedForkedSync(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestBoundedForkedSync64Full(t *testing.T)  { testBoundedForkedSync(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestBoundedForkedSync64Fast(t *testing.T)  { testBoundedForkedSync(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestBoundedForkedSync64Light(t *testing.T) { testBoundedForkedSync(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testBoundedForkedSync(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							|  |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a long enough forked chain | 
					
						
							|  |  |  | 	common, fork := 13, int(MaxForkAncestry+17) | 
					
						
							|  |  |  | 	hashesA, hashesB, headersA, headersB, blocksA, blocksB, receiptsA, receiptsB := tester.makeChainFork(common+fork, fork, tester.genesis, nil, true) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 	tester.newPeer("original", protocol, hashesA, headersA, blocksA, receiptsA) | 
					
						
							|  |  |  | 	tester.newPeer("rewriter", protocol, hashesB, headersB, blocksB, receiptsB) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the peer and make sure all blocks were retrieved | 
					
						
							|  |  |  | 	if err := tester.sync("original", nil, mode); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assertOwnChain(t, tester, common+fork+1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the second peer and ensure that the fork is rejected to being too old | 
					
						
							|  |  |  | 	if err := tester.sync("rewriter", nil, mode); err != errInvalidAncestor { | 
					
						
							|  |  |  | 		t.Fatalf("sync failure mismatch: have %v, want %v", err, errInvalidAncestor) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that chain forks are contained within a certain interval of the current | 
					
						
							|  |  |  | // chain head for short but heavy forks too. These are a bit special because they | 
					
						
							|  |  |  | // take different ancestor lookup paths. | 
					
						
							|  |  |  | func TestBoundedHeavyForkedSync62(t *testing.T)      { testBoundedHeavyForkedSync(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestBoundedHeavyForkedSync63Full(t *testing.T)  { testBoundedHeavyForkedSync(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestBoundedHeavyForkedSync63Fast(t *testing.T)  { testBoundedHeavyForkedSync(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestBoundedHeavyForkedSync64Full(t *testing.T)  { testBoundedHeavyForkedSync(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestBoundedHeavyForkedSync64Fast(t *testing.T)  { testBoundedHeavyForkedSync(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestBoundedHeavyForkedSync64Light(t *testing.T) { testBoundedHeavyForkedSync(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testBoundedHeavyForkedSync(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							|  |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a long enough forked chain | 
					
						
							|  |  |  | 	common, fork := 13, int(MaxForkAncestry+17) | 
					
						
							|  |  |  | 	hashesA, hashesB, headersA, headersB, blocksA, blocksB, receiptsA, receiptsB := tester.makeChainFork(common+fork, fork, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 12:12:13 +02:00
										 |  |  | 	tester.newPeer("original", protocol, hashesA, headersA, blocksA, receiptsA) | 
					
						
							|  |  |  | 	tester.newPeer("heavy-rewriter", protocol, hashesB[MaxForkAncestry-17:], headersB, blocksB, receiptsB) // Root the fork below the ancestor limit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the peer and make sure all blocks were retrieved | 
					
						
							|  |  |  | 	if err := tester.sync("original", nil, mode); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assertOwnChain(t, tester, common+fork+1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Synchronise with the second peer and ensure that the fork is rejected to being too old | 
					
						
							|  |  |  | 	if err := tester.sync("heavy-rewriter", nil, mode); err != errInvalidAncestor { | 
					
						
							|  |  |  | 		t.Fatalf("sync failure mismatch: have %v, want %v", err, errInvalidAncestor) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | // Tests that an inactive downloader will not accept incoming block headers and | 
					
						
							|  |  |  | // bodies. | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | func TestInactiveDownloader62(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check that neither block headers nor bodies are accepted | 
					
						
							|  |  |  | 	if err := tester.downloader.DeliverHeaders("bad peer", []*types.Header{}); err != errNoSyncActive { | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	if err := tester.downloader.DeliverBodies("bad peer", [][]*types.Transaction{}, [][]*types.Header{}); err != errNoSyncActive { | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | // Tests that an inactive downloader will not accept incoming block headers, | 
					
						
							|  |  |  | // bodies and receipts. | 
					
						
							|  |  |  | func TestInactiveDownloader63(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check that neither block headers nor bodies are accepted | 
					
						
							|  |  |  | 	if err := tester.downloader.DeliverHeaders("bad peer", []*types.Header{}); err != errNoSyncActive { | 
					
						
							|  |  |  | 		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := tester.downloader.DeliverBodies("bad peer", [][]*types.Transaction{}, [][]*types.Header{}); err != errNoSyncActive { | 
					
						
							|  |  |  | 		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := tester.downloader.DeliverReceipts("bad peer", [][]*types.Receipt{}); err != errNoSyncActive { | 
					
						
							|  |  |  | 		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | // Tests that a canceled download wipes all previously accumulated state. | 
					
						
							|  |  |  | func TestCancel62(t *testing.T)      { testCancel(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestCancel63Full(t *testing.T)  { testCancel(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestCancel63Fast(t *testing.T)  { testCancel(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestCancel64Full(t *testing.T)  { testCancel(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestCancel64Fast(t *testing.T)  { testCancel(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestCancel64Light(t *testing.T) { testCancel(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testCancel(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 	// Create a small enough block chain to download and the tester | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							|  |  |  | 	if targetBlocks >= MaxHashFetch { | 
					
						
							|  |  |  | 		targetBlocks = MaxHashFetch - 15 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	if targetBlocks >= MaxHeaderFetch { | 
					
						
							|  |  |  | 		targetBlocks = MaxHeaderFetch - 15 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure canceling works with a pristine downloader | 
					
						
							| 
									
										
										
										
											2017-03-22 02:37:24 +02:00
										 |  |  | 	tester.downloader.Cancel() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	if !tester.downloader.queue.Idle() { | 
					
						
							|  |  |  | 		t.Errorf("download queue not idle") | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Synchronise with the peer, but cancel afterwards | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("peer", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-22 02:37:24 +02:00
										 |  |  | 	tester.downloader.Cancel() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	if !tester.downloader.queue.Idle() { | 
					
						
							|  |  |  | 		t.Errorf("download queue not idle") | 
					
						
							| 
									
										
										
										
											2015-06-30 19:05:06 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | // Tests that synchronisation from multiple peers works as intended (multi thread sanity test). | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestMultiSynchronisation62(t *testing.T)      { testMultiSynchronisation(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestMultiSynchronisation63Full(t *testing.T)  { testMultiSynchronisation(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestMultiSynchronisation63Fast(t *testing.T)  { testMultiSynchronisation(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestMultiSynchronisation64Full(t *testing.T)  { testMultiSynchronisation(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestMultiSynchronisation64Fast(t *testing.T)  { testMultiSynchronisation(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestMultiSynchronisation64Light(t *testing.T) { testMultiSynchronisation(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testMultiSynchronisation(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | 	// Create various peers with various parts of the chain | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	targetPeers := 8 | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | 	targetBlocks := targetPeers*blockCacheLimit - 15 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | 	for i := 0; i < targetPeers; i++ { | 
					
						
							|  |  |  | 		id := fmt.Sprintf("peer #%d", i) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		tester.newPeer(id, protocol, hashes[i*blockCacheLimit:], headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("peer #0", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							| 
									
										
										
										
											2015-06-12 14:36:44 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | // Tests that synchronisations behave well in multi-version protocol environments | 
					
						
							| 
									
										
										
										
											2016-03-15 11:27:49 -07:00
										 |  |  | // and not wreak havoc on other nodes in the network. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestMultiProtoSynchronisation62(t *testing.T)      { testMultiProtoSync(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestMultiProtoSynchronisation63Full(t *testing.T)  { testMultiProtoSync(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestMultiProtoSynchronisation63Fast(t *testing.T)  { testMultiProtoSync(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestMultiProtoSynchronisation64Full(t *testing.T)  { testMultiProtoSync(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestMultiProtoSynchronisation64Fast(t *testing.T)  { testMultiProtoSync(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestMultiProtoSynchronisation64Light(t *testing.T) { testMultiProtoSync(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testMultiProtoSync(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create peers of every type | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester.newPeer("peer 62", 62, hashes, headers, blocks, nil) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer 63", 63, hashes, headers, blocks, receipts) | 
					
						
							|  |  |  | 	tester.newPeer("peer 64", 64, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise with the requested peer and make sure all blocks were retrieved | 
					
						
							|  |  |  | 	if err := tester.sync(fmt.Sprintf("peer %d", protocol), nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | 	// Check that no peers have been dropped off | 
					
						
							| 
									
										
										
										
											2016-07-21 11:36:38 +02:00
										 |  |  | 	for _, version := range []int{62, 63, 64} { | 
					
						
							| 
									
										
										
										
											2015-10-02 13:20:41 +03:00
										 |  |  | 		peer := fmt.Sprintf("peer %d", version) | 
					
						
							|  |  |  | 		if _, ok := tester.peerHashes[peer]; !ok { | 
					
						
							|  |  |  | 			t.Errorf("%s dropped", peer) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | // Tests that if a block is empty (e.g. header only), no body request should be | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | // made, and instead the header should be assembled into a whole block in itself. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestEmptyShortCircuit62(t *testing.T)      { testEmptyShortCircuit(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestEmptyShortCircuit63Full(t *testing.T)  { testEmptyShortCircuit(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestEmptyShortCircuit63Fast(t *testing.T)  { testEmptyShortCircuit(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestEmptyShortCircuit64Full(t *testing.T)  { testEmptyShortCircuit(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestEmptyShortCircuit64Fast(t *testing.T)  { testEmptyShortCircuit(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestEmptyShortCircuit64Light(t *testing.T) { testEmptyShortCircuit(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testEmptyShortCircuit(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a block chain to download | 
					
						
							|  |  |  | 	targetBlocks := 2*blockCacheLimit - 15 | 
					
						
							|  |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Instrument the downloader to signal body requests | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	bodiesHave, receiptsHave := int32(0), int32(0) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	tester.downloader.bodyFetchHook = func(headers []*types.Header) { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		atomic.AddInt32(&bodiesHave, int32(len(headers))) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	tester.downloader.receiptFetchHook = func(headers []*types.Header) { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		atomic.AddInt32(&receiptsHave, int32(len(headers))) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Synchronise with the peer and make sure all blocks were retrieved | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("peer", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	// Validate the number of block bodies that should have been requested | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	bodiesNeeded, receiptsNeeded := 0, 0 | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	for _, block := range blocks { | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 		if mode != LightSync && block != tester.genesis && (len(block.Transactions()) > 0 || len(block.Uncles()) > 0) { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 			bodiesNeeded++ | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-05 19:37:56 +03:00
										 |  |  | 	for hash, receipt := range receipts { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if mode == FastSync && len(receipt) > 0 && headers[hash].Number.Uint64() <= tester.downloader.queue.fastSyncPivot { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 			receiptsNeeded++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	if int(bodiesHave) != bodiesNeeded { | 
					
						
							|  |  |  | 		t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave, bodiesNeeded) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	if int(receiptsHave) != receiptsNeeded { | 
					
						
							|  |  |  | 		t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave, receiptsNeeded) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | // Tests that headers are enqueued continuously, preventing malicious nodes from | 
					
						
							|  |  |  | // stalling the downloader by feeding gapped header chains. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestMissingHeaderAttack62(t *testing.T)      { testMissingHeaderAttack(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestMissingHeaderAttack63Full(t *testing.T)  { testMissingHeaderAttack(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestMissingHeaderAttack63Fast(t *testing.T)  { testMissingHeaderAttack(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestMissingHeaderAttack64Full(t *testing.T)  { testMissingHeaderAttack(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestMissingHeaderAttack64Fast(t *testing.T)  { testMissingHeaderAttack(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestMissingHeaderAttack64Light(t *testing.T) { testMissingHeaderAttack(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testMissingHeaderAttack(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							|  |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 	// Attempt a full sync with an attacker feeding gapped headers | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("attack", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 	missing := targetBlocks / 2 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	delete(tester.peerHeaders["attack"], hashes[missing]) | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("attack", nil, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 		t.Fatalf("succeeded attacker synchronisation") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Synchronise with the valid peer and make sure sync succeeds | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("valid", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("valid", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that if requested headers are shifted (i.e. first is missing), the queue | 
					
						
							|  |  |  | // detects the invalid numbering. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestShiftedHeaderAttack62(t *testing.T)      { testShiftedHeaderAttack(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestShiftedHeaderAttack63Full(t *testing.T)  { testShiftedHeaderAttack(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestShiftedHeaderAttack63Fast(t *testing.T)  { testShiftedHeaderAttack(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestShiftedHeaderAttack64Full(t *testing.T)  { testShiftedHeaderAttack(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestShiftedHeaderAttack64Fast(t *testing.T)  { testShiftedHeaderAttack(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestShiftedHeaderAttack64Light(t *testing.T) { testShiftedHeaderAttack(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testShiftedHeaderAttack(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							|  |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 	// Attempt a full sync with an attacker feeding shifted headers | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("attack", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	delete(tester.peerHeaders["attack"], hashes[len(hashes)-2]) | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 	delete(tester.peerBlocks["attack"], hashes[len(hashes)-2]) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	delete(tester.peerReceipts["attack"], hashes[len(hashes)-2]) | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("attack", nil, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 		t.Fatalf("succeeded attacker synchronisation") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Synchronise with the valid peer and make sure sync succeeds | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("valid", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("valid", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that upon detecting an invalid header, the recent ones are rolled back | 
					
						
							| 
									
										
										
										
											2015-12-29 14:01:08 +02:00
										 |  |  | // for various failure scenarios. Afterwards a full sync is attempted to make | 
					
						
							|  |  |  | // sure no state was corrupted. | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | func TestInvalidHeaderRollback63Fast(t *testing.T)  { testInvalidHeaderRollback(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestInvalidHeaderRollback64Fast(t *testing.T)  { testInvalidHeaderRollback(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestInvalidHeaderRollback64Light(t *testing.T) { testInvalidHeaderRollback(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 	targetBlocks := 3*fsHeaderSafetyNet + fsPivotInterval + fsMinFullBlocks | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Attempt to sync with an attacker that feeds junk during the fast sync phase. | 
					
						
							|  |  |  | 	// This should result in the last fsHeaderSafetyNet headers being rolled back. | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	tester.newPeer("fast-attack", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	missing := fsHeaderSafetyNet + MaxHeaderFetch + 1 | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	delete(tester.peerHeaders["fast-attack"], hashes[len(hashes)-missing]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("fast-attack", nil, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 		t.Fatalf("succeeded fast attacker synchronisation") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 	if head := tester.CurrentHeader().Number.Int64(); int(head) > MaxHeaderFetch { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		t.Errorf("rollback head mismatch: have %v, want at most %v", head, MaxHeaderFetch) | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Attempt to sync with an attacker that feeds junk during the block import phase. | 
					
						
							|  |  |  | 	// This should result in both the last fsHeaderSafetyNet number of headers being | 
					
						
							|  |  |  | 	// rolled back, and also the pivot point being reverted to a non-block status. | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	tester.newPeer("block-attack", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	missing = 3*fsHeaderSafetyNet + MaxHeaderFetch + 1 | 
					
						
							| 
									
										
										
										
											2016-04-19 12:27:37 +03:00
										 |  |  | 	delete(tester.peerHeaders["fast-attack"], hashes[len(hashes)-missing]) // Make sure the fast-attacker doesn't fill in | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	delete(tester.peerHeaders["block-attack"], hashes[len(hashes)-missing]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("block-attack", nil, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 		t.Fatalf("succeeded block attacker synchronisation") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 	if head := tester.CurrentHeader().Number.Int64(); int(head) > 2*fsHeaderSafetyNet+MaxHeaderFetch { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	if mode == FastSync { | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 		if head := tester.CurrentBlock().NumberU64(); head != 0 { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 			t.Errorf("fast sync pivot block #%d not rolled back", head) | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Attempt to sync with an attacker that withholds promised blocks after the | 
					
						
							|  |  |  | 	// fast sync pivot point. This could be a trial to leave the node with a bad | 
					
						
							|  |  |  | 	// but already imported pivot block. | 
					
						
							|  |  |  | 	tester.newPeer("withhold-attack", protocol, hashes, headers, blocks, receipts) | 
					
						
							|  |  |  | 	missing = 3*fsHeaderSafetyNet + MaxHeaderFetch + 1 | 
					
						
							| 
									
										
										
										
											2015-09-15 13:33:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 	tester.downloader.fsPivotFails = 0 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester.downloader.syncInitHook = func(uint64, uint64) { | 
					
						
							|  |  |  | 		for i := missing; i <= len(hashes); i++ { | 
					
						
							|  |  |  | 			delete(tester.peerHeaders["withhold-attack"], hashes[len(hashes)-i]) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		tester.downloader.syncInitHook = nil | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("withhold-attack", nil, mode); err == nil { | 
					
						
							|  |  |  | 		t.Fatalf("succeeded withholding attacker synchronisation") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 	if head := tester.CurrentHeader().Number.Int64(); int(head) > 2*fsHeaderSafetyNet+MaxHeaderFetch { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch) | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if mode == FastSync { | 
					
						
							| 
									
										
										
										
											2017-06-27 16:15:29 +01:00
										 |  |  | 		if head := tester.CurrentBlock().NumberU64(); head != 0 { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 			t.Errorf("fast sync pivot block #%d not rolled back", head) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 	tester.downloader.fsPivotFails = fsCriticalTrials | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise with the valid peer and make sure sync succeeds. Since the last | 
					
						
							|  |  |  | 	// rollback should also disable fast syncing for this process, verify that we | 
					
						
							|  |  |  | 	// did a fresh full sync. Note, we can't assert anything about the receipts | 
					
						
							| 
									
										
										
										
											2016-03-15 11:27:49 -07:00
										 |  |  | 	// since we won't purge the database of them, hence we can't use assertOwnChain. | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester.newPeer("valid", protocol, hashes, headers, blocks, receipts) | 
					
						
							|  |  |  | 	if err := tester.sync("valid", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 		t.Fatalf("failed to synchronise blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if hs := len(tester.ownHeaders); hs != len(headers) { | 
					
						
							|  |  |  | 		t.Fatalf("synchronised headers mismatch: have %v, want %v", hs, len(headers)) | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if mode != LightSync { | 
					
						
							|  |  |  | 		if bs := len(tester.ownBlocks); bs != len(blocks) { | 
					
						
							|  |  |  | 			t.Fatalf("synchronised blocks mismatch: have %v, want %v", bs, len(blocks)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-09 14:40:18 +03:00
										 |  |  | // Tests that a peer advertising an high TD doesn't get to stall the downloader | 
					
						
							|  |  |  | // afterwards by not sending any useful hashes. | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | func TestHighTDStarvationAttack62(t *testing.T)      { testHighTDStarvationAttack(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestHighTDStarvationAttack63Full(t *testing.T)  { testHighTDStarvationAttack(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestHighTDStarvationAttack63Fast(t *testing.T)  { testHighTDStarvationAttack(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestHighTDStarvationAttack64Full(t *testing.T)  { testHighTDStarvationAttack(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestHighTDStarvationAttack64Fast(t *testing.T)  { testHighTDStarvationAttack(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestHighTDStarvationAttack64Light(t *testing.T) { testHighTDStarvationAttack(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testHighTDStarvationAttack(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(0, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("attack", protocol, []common.Hash{hashes[0]}, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	if err := tester.sync("attack", big.NewInt(1000000), mode); err != errStallingPeer { | 
					
						
							| 
									
										
										
										
											2015-07-09 14:40:18 +03:00
										 |  |  | 		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | // Tests that misbehaving peers are disconnected, whilst behaving ones are not. | 
					
						
							| 
									
										
										
										
											2015-08-14 21:25:41 +03:00
										 |  |  | func TestBlockHeaderAttackerDropping62(t *testing.T) { testBlockHeaderAttackerDropping(t, 62) } | 
					
						
							|  |  |  | func TestBlockHeaderAttackerDropping63(t *testing.T) { testBlockHeaderAttackerDropping(t, 63) } | 
					
						
							|  |  |  | func TestBlockHeaderAttackerDropping64(t *testing.T) { testBlockHeaderAttackerDropping(t, 64) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testBlockHeaderAttackerDropping(t *testing.T, protocol int) { | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 	// Define the disconnection requirement for individual hash fetch errors | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		result error | 
					
						
							|  |  |  | 		drop   bool | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2016-02-25 18:36:42 +02:00
										 |  |  | 		{nil, false},                        // Sync succeeded, all is well | 
					
						
							|  |  |  | 		{errBusy, false},                    // Sync is already in progress, no problem | 
					
						
							|  |  |  | 		{errUnknownPeer, false},             // Peer is unknown, was already dropped, don't double drop | 
					
						
							|  |  |  | 		{errBadPeer, true},                  // Peer was deemed bad for some reason, drop it | 
					
						
							|  |  |  | 		{errStallingPeer, true},             // Peer was detected to be stalling, drop it | 
					
						
							|  |  |  | 		{errNoPeers, false},                 // No peers to download from, soft race, no issue | 
					
						
							|  |  |  | 		{errTimeout, true},                  // No hashes received in due time, drop the peer | 
					
						
							|  |  |  | 		{errEmptyHeaderSet, true},           // No headers were returned as a response, drop as it's a dead end | 
					
						
							|  |  |  | 		{errPeersUnavailable, true},         // Nobody had the advertised blocks, drop the advertiser | 
					
						
							|  |  |  | 		{errInvalidAncestor, true},          // Agreed upon ancestor is not acceptable, drop the chain rewriter | 
					
						
							|  |  |  | 		{errInvalidChain, true},             // Hash chain was detected as invalid, definitely drop | 
					
						
							|  |  |  | 		{errInvalidBlock, false},            // A bad peer was detected, but not the sync origin | 
					
						
							|  |  |  | 		{errInvalidBody, false},             // A bad peer was detected, but not the sync origin | 
					
						
							|  |  |  | 		{errInvalidReceipt, false},          // A bad peer was detected, but not the sync origin | 
					
						
							|  |  |  | 		{errCancelBlockFetch, false},        // Synchronisation was canceled, origin may be innocent, don't drop | 
					
						
							|  |  |  | 		{errCancelHeaderFetch, false},       // Synchronisation was canceled, origin may be innocent, don't drop | 
					
						
							|  |  |  | 		{errCancelBodyFetch, false},         // Synchronisation was canceled, origin may be innocent, don't drop | 
					
						
							|  |  |  | 		{errCancelReceiptFetch, false},      // Synchronisation was canceled, origin may be innocent, don't drop | 
					
						
							|  |  |  | 		{errCancelHeaderProcessing, false},  // Synchronisation was canceled, origin may be innocent, don't drop | 
					
						
							|  |  |  | 		{errCancelContentProcessing, false}, // Synchronisation was canceled, origin may be innocent, don't drop | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Run the tests and check disconnection status | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 	for i, tt := range tests { | 
					
						
							|  |  |  | 		// Register a new peer and ensure it's presence | 
					
						
							|  |  |  | 		id := fmt.Sprintf("test %d", i) | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 		if err := tester.newPeer(id, protocol, []common.Hash{tester.genesis.Hash()}, nil, nil, nil); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 			t.Fatalf("test %d: failed to register new peer: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, ok := tester.peerHashes[id]; !ok { | 
					
						
							|  |  |  | 			t.Fatalf("test %d: registered peer not found", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Simulate a synchronisation and check the required result | 
					
						
							|  |  |  | 		tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 		tester.downloader.Synchronise(id, tester.genesis.Hash(), big.NewInt(1000), FullSync) | 
					
						
							| 
									
										
										
										
											2015-06-11 18:13:13 +03:00
										 |  |  | 		if _, ok := tester.peerHashes[id]; !ok != tt.drop { | 
					
						
							|  |  |  | 			t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-12 13:35:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | // Tests that synchronisation progress (origin block number, current block number | 
					
						
							|  |  |  | // and highest block number) is tracked and updated correctly. | 
					
						
							|  |  |  | func TestSyncProgress62(t *testing.T)      { testSyncProgress(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestSyncProgress63Full(t *testing.T)  { testSyncProgress(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestSyncProgress63Fast(t *testing.T)  { testSyncProgress(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestSyncProgress64Full(t *testing.T)  { testSyncProgress(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestSyncProgress64Fast(t *testing.T)  { testSyncProgress(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestSyncProgress64Light(t *testing.T) { testSyncProgress(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Set a sync init hook to catch progress changes | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	starting := make(chan struct{}) | 
					
						
							|  |  |  | 	progress := make(chan struct{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester.downloader.syncInitHook = func(origin, latest uint64) { | 
					
						
							|  |  |  | 		starting <- struct{}{} | 
					
						
							|  |  |  | 		<-progress | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Retrieve the sync progress and ensure they are zero (pristine sync) | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, 0) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise half the blocks and check initial progress | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer-half", protocol, hashes[targetBlocks/2:], headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	pending := new(sync.WaitGroup) | 
					
						
							|  |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("peer-half", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != uint64(targetBlocks/2+1) { | 
					
						
							|  |  |  | 		t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, targetBlocks/2+1) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise all the blocks and check continuation progress | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("peer-full", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("peer-full", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != uint64(targetBlocks/2+1) || progress.CurrentBlock != uint64(targetBlocks/2+1) || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, targetBlocks/2+1, targetBlocks/2+1, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check final progress after successful sync | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != uint64(targetBlocks/2+1) || progress.CurrentBlock != uint64(targetBlocks) || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Final progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, targetBlocks/2+1, targetBlocks, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | // Tests that synchronisation progress (origin block number and highest block | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | // number) is tracked and updated correctly in case of a fork (or manual head | 
					
						
							|  |  |  | // revertal). | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | func TestForkedSyncProgress62(t *testing.T)      { testForkedSyncProgress(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestForkedSyncProgress63Full(t *testing.T)  { testForkedSyncProgress(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestForkedSyncProgress63Fast(t *testing.T)  { testForkedSyncProgress(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestForkedSyncProgress64Full(t *testing.T)  { testForkedSyncProgress(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestForkedSyncProgress64Fast(t *testing.T)  { testForkedSyncProgress(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestForkedSyncProgress64Light(t *testing.T) { testForkedSyncProgress(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	// Create a forked chain to simulate origin revertal | 
					
						
							|  |  |  | 	common, fork := MaxHashFetch, 2*MaxHashFetch | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashesA, hashesB, headersA, headersB, blocksA, blocksB, receiptsA, receiptsB := tester.makeChainFork(common+fork, fork, tester.genesis, nil, true) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Set a sync init hook to catch progress changes | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	starting := make(chan struct{}) | 
					
						
							|  |  |  | 	progress := make(chan struct{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester.downloader.syncInitHook = func(origin, latest uint64) { | 
					
						
							|  |  |  | 		starting <- struct{}{} | 
					
						
							|  |  |  | 		<-progress | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Retrieve the sync progress and ensure they are zero (pristine sync) | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, 0) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise with one of the forks and check progress | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("fork A", protocol, hashesA, headersA, blocksA, receiptsA) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	pending := new(sync.WaitGroup) | 
					
						
							|  |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("fork A", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != uint64(len(hashesA)-1) { | 
					
						
							|  |  |  | 		t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, len(hashesA)-1) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Simulate a successful sync above the fork | 
					
						
							| 
									
										
										
										
											2015-10-07 12:14:30 +03:00
										 |  |  | 	tester.downloader.syncStatsChainOrigin = tester.downloader.syncStatsChainHeight | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise with the second fork and check progress resets | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("fork B", protocol, hashesB, headersB, blocksB, receiptsB) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("fork B", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != uint64(common) || progress.CurrentBlock != uint64(len(hashesA)-1) || progress.HighestBlock != uint64(len(hashesB)-1) { | 
					
						
							|  |  |  | 		t.Fatalf("Forking progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, common, len(hashesA)-1, len(hashesB)-1) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check final progress after successful sync | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != uint64(common) || progress.CurrentBlock != uint64(len(hashesB)-1) || progress.HighestBlock != uint64(len(hashesB)-1) { | 
					
						
							|  |  |  | 		t.Fatalf("Final progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, common, len(hashesB)-1, len(hashesB)-1) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | // Tests that if synchronisation is aborted due to some failure, then the progress | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | // origin is not updated in the next sync cycle, as it should be considered the | 
					
						
							|  |  |  | // continuation of the previous sync and not a new instance. | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | func TestFailedSyncProgress62(t *testing.T)      { testFailedSyncProgress(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestFailedSyncProgress63Full(t *testing.T)  { testFailedSyncProgress(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestFailedSyncProgress63Fast(t *testing.T)  { testFailedSyncProgress(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestFailedSyncProgress64Full(t *testing.T)  { testFailedSyncProgress(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestFailedSyncProgress64Fast(t *testing.T)  { testFailedSyncProgress(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestFailedSyncProgress64Light(t *testing.T) { testFailedSyncProgress(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	// Create a small enough block chain to download | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Set a sync init hook to catch progress changes | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	starting := make(chan struct{}) | 
					
						
							|  |  |  | 	progress := make(chan struct{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester.downloader.syncInitHook = func(origin, latest uint64) { | 
					
						
							|  |  |  | 		starting <- struct{}{} | 
					
						
							|  |  |  | 		<-progress | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Retrieve the sync progress and ensure they are zero (pristine sync) | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, 0) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Attempt a full sync with a faulty peer | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("faulty", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	missing := targetBlocks / 2 | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 	delete(tester.peerHeaders["faulty"], hashes[missing]) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	delete(tester.peerBlocks["faulty"], hashes[missing]) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	delete(tester.peerReceipts["faulty"], hashes[missing]) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pending := new(sync.WaitGroup) | 
					
						
							|  |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("faulty", nil, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic("succeeded faulty synchronisation") | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise with a good peer and check that the progress origin remind the same after a failure | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("valid", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("valid", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock > uint64(targetBlocks/2) || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/0-%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, targetBlocks/2, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check final progress after successful sync | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock > uint64(targetBlocks/2) || progress.CurrentBlock != uint64(targetBlocks) || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Final progress mismatch: have %v/%v/%v, want 0-%v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, targetBlocks/2, targetBlocks, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that if an attacker fakes a chain height, after the attack is detected, | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | // the progress height is successfully reduced at the next sync invocation. | 
					
						
							|  |  |  | func TestFakedSyncProgress62(t *testing.T)      { testFakedSyncProgress(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestFakedSyncProgress63Full(t *testing.T)  { testFakedSyncProgress(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestFakedSyncProgress63Fast(t *testing.T)  { testFakedSyncProgress(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestFakedSyncProgress64Full(t *testing.T)  { testFakedSyncProgress(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestFakedSyncProgress64Fast(t *testing.T)  { testFakedSyncProgress(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestFakedSyncProgress64Light(t *testing.T) { testFakedSyncProgress(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							| 
									
										
										
										
											2015-11-18 10:48:26 +01:00
										 |  |  | 	t.Parallel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	// Create a small block chain | 
					
						
							|  |  |  | 	targetBlocks := blockCacheLimit - 15 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks+3, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Set a sync init hook to catch progress changes | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	starting := make(chan struct{}) | 
					
						
							|  |  |  | 	progress := make(chan struct{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tester.downloader.syncInitHook = func(origin, latest uint64) { | 
					
						
							|  |  |  | 		starting <- struct{}{} | 
					
						
							|  |  |  | 		<-progress | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Retrieve the sync progress and ensure they are zero (pristine sync) | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, 0) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	//  Create and sync with an attacker that promises a higher chain than available | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("attack", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	for i := 1; i < 3; i++ { | 
					
						
							| 
									
										
										
										
											2015-09-28 19:27:31 +03:00
										 |  |  | 		delete(tester.peerHeaders["attack"], hashes[i]) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		delete(tester.peerBlocks["attack"], hashes[i]) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		delete(tester.peerReceipts["attack"], hashes[i]) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pending := new(sync.WaitGroup) | 
					
						
							|  |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("attack", nil, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic("succeeded attacker synchronisation") | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock != 0 || progress.HighestBlock != uint64(targetBlocks+3) { | 
					
						
							|  |  |  | 		t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, 0, targetBlocks+3) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	// Synchronise with a good peer and check that the progress height has been reduced to the true value | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	tester.newPeer("valid", protocol, hashes[3:], headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	pending.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer pending.Done() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 		if err := tester.sync("valid", nil, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-06 08:54:25 +03:00
										 |  |  | 			panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	<-starting | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock != 0 || progress.CurrentBlock > uint64(targetBlocks) || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/0-%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, 0, targetBlocks, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	progress <- struct{}{} | 
					
						
							|  |  |  | 	pending.Wait() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check final progress after successful sync | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	if progress := tester.downloader.Progress(); progress.StartingBlock > uint64(targetBlocks) || progress.CurrentBlock != uint64(targetBlocks) || progress.HighestBlock != uint64(targetBlocks) { | 
					
						
							|  |  |  | 		t.Fatalf("Final progress mismatch: have %v/%v/%v, want 0-%v/%v/%v", progress.StartingBlock, progress.CurrentBlock, progress.HighestBlock, targetBlocks, targetBlocks, targetBlocks) | 
					
						
							| 
									
										
										
										
											2015-10-13 12:04:25 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-09 19:02:54 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This test reproduces an issue where unexpected deliveries would | 
					
						
							|  |  |  | // block indefinitely if they arrived at the right time. | 
					
						
							|  |  |  | func TestDeliverHeadersHang62(t *testing.T)      { testDeliverHeadersHang(t, 62, FullSync) } | 
					
						
							|  |  |  | func TestDeliverHeadersHang63Full(t *testing.T)  { testDeliverHeadersHang(t, 63, FullSync) } | 
					
						
							|  |  |  | func TestDeliverHeadersHang63Fast(t *testing.T)  { testDeliverHeadersHang(t, 63, FastSync) } | 
					
						
							|  |  |  | func TestDeliverHeadersHang64Full(t *testing.T)  { testDeliverHeadersHang(t, 64, FullSync) } | 
					
						
							|  |  |  | func TestDeliverHeadersHang64Fast(t *testing.T)  { testDeliverHeadersHang(t, 64, FastSync) } | 
					
						
							|  |  |  | func TestDeliverHeadersHang64Light(t *testing.T) { testDeliverHeadersHang(t, 64, LightSync) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | type floodingTestPeer struct { | 
					
						
							|  |  |  | 	peer   Peer | 
					
						
							|  |  |  | 	tester *downloadTester | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ftp *floodingTestPeer) Head() (common.Hash, *big.Int) { return ftp.peer.Head() } | 
					
						
							|  |  |  | func (ftp *floodingTestPeer) RequestHeadersByHash(hash common.Hash, count int, skip int, reverse bool) error { | 
					
						
							|  |  |  | 	return ftp.peer.RequestHeadersByHash(hash, count, skip, reverse) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (ftp *floodingTestPeer) RequestBodies(hashes []common.Hash) error { | 
					
						
							|  |  |  | 	return ftp.peer.RequestBodies(hashes) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (ftp *floodingTestPeer) RequestReceipts(hashes []common.Hash) error { | 
					
						
							|  |  |  | 	return ftp.peer.RequestReceipts(hashes) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (ftp *floodingTestPeer) RequestNodeData(hashes []common.Hash) error { | 
					
						
							|  |  |  | 	return ftp.peer.RequestNodeData(hashes) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ftp *floodingTestPeer) RequestHeadersByNumber(from uint64, count, skip int, reverse bool) error { | 
					
						
							|  |  |  | 	deliveriesDone := make(chan struct{}, 500) | 
					
						
							|  |  |  | 	for i := 0; i < cap(deliveriesDone); i++ { | 
					
						
							|  |  |  | 		peer := fmt.Sprintf("fake-peer%d", i) | 
					
						
							|  |  |  | 		go func() { | 
					
						
							|  |  |  | 			ftp.tester.downloader.DeliverHeaders(peer, []*types.Header{{}, {}, {}, {}}) | 
					
						
							|  |  |  | 			deliveriesDone <- struct{}{} | 
					
						
							|  |  |  | 		}() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Deliver the actual requested headers. | 
					
						
							|  |  |  | 	go ftp.peer.RequestHeadersByNumber(from, count, skip, reverse) | 
					
						
							|  |  |  | 	// None of the extra deliveries should block. | 
					
						
							|  |  |  | 	timeout := time.After(15 * time.Second) | 
					
						
							|  |  |  | 	for i := 0; i < cap(deliveriesDone); i++ { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-deliveriesDone: | 
					
						
							|  |  |  | 		case <-timeout: | 
					
						
							|  |  |  | 			panic("blocked") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | func testDeliverHeadersHang(t *testing.T, protocol int, mode SyncMode) { | 
					
						
							|  |  |  | 	t.Parallel() | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	master := newTester() | 
					
						
							|  |  |  | 	defer master.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hashes, headers, blocks, receipts := master.makeChain(5, 0, master.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 	for i := 0; i < 200; i++ { | 
					
						
							|  |  |  | 		tester := newTester() | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 		tester.peerDb = master.peerDb | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 		tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) | 
					
						
							|  |  |  | 		// Whenever the downloader requests headers, flood it with | 
					
						
							|  |  |  | 		// a lot of unrequested header deliveries. | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 		tester.downloader.peers.peers["peer"].peer = &floodingTestPeer{ | 
					
						
							|  |  |  | 			tester.downloader.peers.peers["peer"].peer, | 
					
						
							|  |  |  | 			tester, | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-28 13:25:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 		if err := tester.sync("peer", nil, mode); err != nil { | 
					
						
							|  |  |  | 			t.Errorf("sync failed: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 		tester.terminate() | 
					
						
							| 
									
										
										
										
											2015-11-13 16:08:15 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that if fast sync aborts in the critical section, it can restart a few | 
					
						
							|  |  |  | // times before giving up. | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | func TestFastCriticalRestartsFail63(t *testing.T) { testFastCriticalRestarts(t, 63, false) } | 
					
						
							|  |  |  | func TestFastCriticalRestartsFail64(t *testing.T) { testFastCriticalRestarts(t, 64, false) } | 
					
						
							|  |  |  | func TestFastCriticalRestartsCont63(t *testing.T) { testFastCriticalRestarts(t, 63, true) } | 
					
						
							|  |  |  | func TestFastCriticalRestartsCont64(t *testing.T) { testFastCriticalRestarts(t, 64, true) } | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | func testFastCriticalRestarts(t *testing.T, protocol int, progress bool) { | 
					
						
							|  |  |  | 	tester := newTester() | 
					
						
							|  |  |  | 	defer tester.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 	// Create a large enough blockchin to actually fast sync on | 
					
						
							|  |  |  | 	targetBlocks := fsMinFullBlocks + 2*fsPivotInterval - 15 | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	hashes, headers, blocks, receipts := tester.makeChain(targetBlocks, 0, tester.genesis, nil, false) | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 	// Create a tester peer with a critical section header missing (force failures) | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 	tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 	delete(tester.peerHeaders["peer"], hashes[fsMinFullBlocks-1]) | 
					
						
							|  |  |  | 	tester.downloader.dropPeer = func(id string) {} // We reuse the same "faulty" peer throughout the test | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove all possible pivot state roots and slow down replies (test failure resets later) | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 	for i := 0; i < fsPivotInterval; i++ { | 
					
						
							|  |  |  | 		tester.peerMissingStates["peer"][headers[hashes[fsMinFullBlocks+i]].Root] = true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 	(tester.downloader.peers.peers["peer"].peer).(*downloadTesterPeer).setDelay(500 * time.Millisecond) // Enough to reach the critical section | 
					
						
							| 
									
										
										
										
											2016-06-13 13:01:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 	// Synchronise with the peer a few times and make sure they fail until the retry limit | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	for i := 0; i < int(fsCriticalTrials)-1; i++ { | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 		// Attempt a sync and ensure it fails properly | 
					
						
							|  |  |  | 		if err := tester.sync("peer", nil, FastSync); err == nil { | 
					
						
							|  |  |  | 			t.Fatalf("failing fast sync succeeded: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 		time.Sleep(150 * time.Millisecond) // Make sure no in-flight requests remain | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 		// If it's the first failure, pivot should be locked => reenable all others to detect pivot changes | 
					
						
							|  |  |  | 		if i == 0 { | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 			if tester.downloader.fsPivotLock == nil { | 
					
						
							|  |  |  | 				time.Sleep(400 * time.Millisecond) // Make sure the first huge timeout expires too | 
					
						
							|  |  |  | 				t.Fatalf("pivot block not locked in after critical section failure") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 			tester.lock.Lock() | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 			tester.peerHeaders["peer"][hashes[fsMinFullBlocks-1]] = headers[hashes[fsMinFullBlocks-1]] | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 			tester.peerMissingStates["peer"] = map[common.Hash]bool{tester.downloader.fsPivotLock.Root: true} | 
					
						
							| 
									
										
										
										
											2017-08-08 20:10:09 +03:00
										 |  |  | 			(tester.downloader.peers.peers["peer"].peer).(*downloadTesterPeer).setDelay(0) | 
					
						
							| 
									
										
										
										
											2016-06-01 18:07:25 +03:00
										 |  |  | 			tester.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	// Return all nodes if we're testing fast sync progression | 
					
						
							|  |  |  | 	if progress { | 
					
						
							|  |  |  | 		tester.lock.Lock() | 
					
						
							|  |  |  | 		tester.peerMissingStates["peer"] = map[common.Hash]bool{} | 
					
						
							|  |  |  | 		tester.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := tester.sync("peer", nil, FastSync); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to synchronise blocks in progressed fast sync: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 		time.Sleep(150 * time.Millisecond) // Make sure no in-flight requests remain | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if fails := atomic.LoadUint32(&tester.downloader.fsPivotFails); fails != 1 { | 
					
						
							|  |  |  | 			t.Fatalf("progressed pivot trial count mismatch: have %v, want %v", fails, 1) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 		assertOwnChain(t, tester, targetBlocks+1) | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		if err := tester.sync("peer", nil, FastSync); err == nil { | 
					
						
							|  |  |  | 			t.Fatalf("succeeded to synchronise blocks in failed fast sync") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 		time.Sleep(150 * time.Millisecond) // Make sure no in-flight requests remain | 
					
						
							| 
									
										
										
										
											2016-10-31 13:55:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if fails := atomic.LoadUint32(&tester.downloader.fsPivotFails); fails != fsCriticalTrials { | 
					
						
							|  |  |  | 			t.Fatalf("failed pivot trial count mismatch: have %v, want %v", fails, fsCriticalTrials) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | 	// Retry limit exhausted, downloader will switch to full sync, should succeed | 
					
						
							|  |  |  | 	if err := tester.sync("peer", nil, FastSync); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to synchronise blocks in slow sync: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 17:26:44 +02:00
										 |  |  | 	// Note, we can't assert the chain here because the test asserter assumes sync | 
					
						
							|  |  |  | 	// completed using a single mode of operation, whereas fast-then-slow can result | 
					
						
							|  |  |  | 	// in arbitrary intermediate state that's not cleanly verifiable. | 
					
						
							| 
									
										
										
										
											2016-06-02 12:37:14 +03:00
										 |  |  | } |