github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/eth/handler_test.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package eth 18 19 import ( 20 "math" 21 "math/big" 22 "math/rand" 23 "testing" 24 "time" 25 26 "github.com/SmartMeshFoundation/Spectrum/common" 27 "github.com/SmartMeshFoundation/Spectrum/consensus/ethash" 28 "github.com/SmartMeshFoundation/Spectrum/core" 29 "github.com/SmartMeshFoundation/Spectrum/core/state" 30 "github.com/SmartMeshFoundation/Spectrum/core/types" 31 "github.com/SmartMeshFoundation/Spectrum/core/vm" 32 "github.com/SmartMeshFoundation/Spectrum/crypto" 33 "github.com/SmartMeshFoundation/Spectrum/eth/downloader" 34 "github.com/SmartMeshFoundation/Spectrum/ethdb" 35 "github.com/SmartMeshFoundation/Spectrum/event" 36 "github.com/SmartMeshFoundation/Spectrum/p2p" 37 "github.com/SmartMeshFoundation/Spectrum/params" 38 ) 39 40 var bigTxGas = new(big.Int).SetUint64(params.TxGas) 41 42 // Tests that protocol versions and modes of operations are matched up properly. 43 func TestProtocolCompatibility(t *testing.T) { 44 // Define the compatibility chart 45 tests := []struct { 46 version uint 47 mode downloader.SyncMode 48 compatible bool 49 }{ 50 {61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true}, 51 {61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true}, 52 } 53 // Make sure anything we screw up is restored 54 backup := ProtocolVersions 55 defer func() { ProtocolVersions = backup }() 56 57 // Try all available compatibility configs and check for errors 58 for i, tt := range tests { 59 ProtocolVersions = []uint{tt.version} 60 61 pm, err := newTestProtocolManager(tt.mode, 0, nil, nil) 62 if pm != nil { 63 defer pm.Stop() 64 } 65 if (err == nil && !tt.compatible) || (err != nil && tt.compatible) { 66 t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible) 67 } 68 } 69 } 70 71 // Tests that block headers can be retrieved from a remote chain based on user queries. 72 func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) } 73 func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) } 74 75 func testGetBlockHeaders(t *testing.T, protocol int) { 76 pm := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil) 77 peer, _ := newTestPeer("peer", protocol, pm, true) 78 defer peer.close() 79 80 // Create a "random" unknown hash for testing 81 var unknown common.Hash 82 for i := range unknown { 83 unknown[i] = byte(i) 84 } 85 // Create a batch of tests for various scenarios 86 limit := uint64(downloader.MaxHeaderFetch) 87 tests := []struct { 88 query *getBlockHeadersData // The query to execute for header retrieval 89 expect []common.Hash // The hashes of the block whose headers are expected 90 }{ 91 // A single random block should be retrievable by hash and number too 92 { 93 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1}, 94 []common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, 95 }, { 96 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1}, 97 []common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, 98 }, 99 // Multiple headers should be retrievable in both directions 100 { 101 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3}, 102 []common.Hash{ 103 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 104 pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(), 105 pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(), 106 }, 107 }, { 108 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true}, 109 []common.Hash{ 110 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 111 pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(), 112 pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(), 113 }, 114 }, 115 // Multiple headers with skip lists should be retrievable 116 { 117 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3}, 118 []common.Hash{ 119 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 120 pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(), 121 pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(), 122 }, 123 }, { 124 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true}, 125 []common.Hash{ 126 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 127 pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(), 128 pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(), 129 }, 130 }, 131 // The chain endpoints should be retrievable 132 { 133 &getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, 134 []common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()}, 135 }, { 136 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1}, 137 []common.Hash{pm.blockchain.CurrentBlock().Hash()}, 138 }, 139 // Ensure protocol limits are honored 140 { 141 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, 142 pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit), 143 }, 144 // Check that requesting more than available is handled gracefully 145 { 146 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, 147 []common.Hash{ 148 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), 149 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(), 150 }, 151 }, { 152 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, 153 []common.Hash{ 154 pm.blockchain.GetBlockByNumber(4).Hash(), 155 pm.blockchain.GetBlockByNumber(0).Hash(), 156 }, 157 }, 158 // Check that requesting more than available is handled gracefully, even if mid skip 159 { 160 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, 161 []common.Hash{ 162 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), 163 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(), 164 }, 165 }, { 166 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, 167 []common.Hash{ 168 pm.blockchain.GetBlockByNumber(4).Hash(), 169 pm.blockchain.GetBlockByNumber(1).Hash(), 170 }, 171 }, 172 // Check a corner case where requesting more can iterate past the endpoints 173 { 174 &getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true}, 175 []common.Hash{ 176 pm.blockchain.GetBlockByNumber(2).Hash(), 177 pm.blockchain.GetBlockByNumber(1).Hash(), 178 pm.blockchain.GetBlockByNumber(0).Hash(), 179 }, 180 }, 181 // Check a corner case where skipping overflow loops back into the chain start 182 { 183 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1}, 184 []common.Hash{ 185 pm.blockchain.GetBlockByNumber(3).Hash(), 186 }, 187 }, 188 // Check a corner case where skipping overflow loops back to the same header 189 { 190 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64}, 191 []common.Hash{ 192 pm.blockchain.GetBlockByNumber(1).Hash(), 193 }, 194 }, 195 // Check that non existing headers aren't returned 196 { 197 &getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, 198 []common.Hash{}, 199 }, { 200 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1}, 201 []common.Hash{}, 202 }, 203 } 204 // Run each of the tests and verify the results against the chain 205 for i, tt := range tests { 206 // Collect the headers to expect in the response 207 headers := []*types.Header{} 208 for _, hash := range tt.expect { 209 headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header()) 210 } 211 // Send the hash request and verify the response 212 p2p.Send(peer.app, 0x03, tt.query) 213 if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil { 214 t.Errorf("test %d: headers mismatch: %v", i, err) 215 } 216 // If the test used number origins, repeat with hashes as the too 217 if tt.query.Origin.Hash == (common.Hash{}) { 218 if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil { 219 tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0 220 221 p2p.Send(peer.app, 0x03, tt.query) 222 if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil { 223 t.Errorf("test %d: headers mismatch: %v", i, err) 224 } 225 } 226 } 227 } 228 } 229 230 // Tests that block contents can be retrieved from a remote chain based on their hashes. 231 func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) } 232 func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) } 233 234 func testGetBlockBodies(t *testing.T, protocol int) { 235 pm := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil) 236 peer, _ := newTestPeer("peer", protocol, pm, true) 237 defer peer.close() 238 239 // Create a batch of tests for various scenarios 240 limit := downloader.MaxBlockFetch 241 tests := []struct { 242 random int // Number of blocks to fetch randomly from the chain 243 explicit []common.Hash // Explicitly requested blocks 244 available []bool // Availability of explicitly requested blocks 245 expected int // Total number of existing blocks to expect 246 }{ 247 {1, nil, nil, 1}, // A single random block should be retrievable 248 {10, nil, nil, 10}, // Multiple random blocks should be retrievable 249 {limit, nil, nil, limit}, // The maximum possible blocks should be retrievable 250 {limit + 1, nil, nil, limit}, // No more than the possible block count should be returned 251 {0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable 252 {0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable 253 {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned 254 255 // Existing and non-existing blocks interleaved should not cause problems 256 {0, []common.Hash{ 257 {}, 258 pm.blockchain.GetBlockByNumber(1).Hash(), 259 {}, 260 pm.blockchain.GetBlockByNumber(10).Hash(), 261 {}, 262 pm.blockchain.GetBlockByNumber(100).Hash(), 263 {}, 264 }, []bool{false, true, false, true, false, true, false}, 3}, 265 } 266 // Run each of the tests and verify the results against the chain 267 for i, tt := range tests { 268 // Collect the hashes to request, and the response to expect 269 hashes, seen := []common.Hash{}, make(map[int64]bool) 270 bodies := []*blockBody{} 271 272 for j := 0; j < tt.random; j++ { 273 for { 274 num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64())) 275 if !seen[num] { 276 seen[num] = true 277 278 block := pm.blockchain.GetBlockByNumber(uint64(num)) 279 hashes = append(hashes, block.Hash()) 280 if len(bodies) < tt.expected { 281 bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) 282 } 283 break 284 } 285 } 286 } 287 for j, hash := range tt.explicit { 288 hashes = append(hashes, hash) 289 if tt.available[j] && len(bodies) < tt.expected { 290 block := pm.blockchain.GetBlockByHash(hash) 291 bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) 292 } 293 } 294 // Send the hash request and verify the response 295 p2p.Send(peer.app, 0x05, hashes) 296 if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil { 297 t.Errorf("test %d: bodies mismatch: %v", i, err) 298 } 299 } 300 } 301 302 // Tests that the node state database can be retrieved based on hashes. 303 func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) } 304 305 func testGetNodeData(t *testing.T, protocol int) { 306 // Define three accounts to simulate transactions with 307 acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 308 acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 309 acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) 310 acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) 311 312 signer := types.HomesteadSigner{} 313 // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test) 314 generator := func(i int, block *core.BlockGen) { 315 switch i { 316 case 0: 317 // In block 1, the test bank sends account #1 some ether. 318 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) 319 block.AddTx(tx) 320 case 1: 321 // In block 2, the test bank sends some more ether to account #1. 322 // acc1Addr passes it on to account #2. 323 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) 324 tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) 325 block.AddTx(tx1) 326 block.AddTx(tx2) 327 case 2: 328 // Block 3 is empty but was mined by account #2. 329 block.SetCoinbase(acc2Addr) 330 block.SetExtra([]byte("yeehaw")) 331 case 3: 332 // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). 333 b2 := block.PrevBlock(1).Header() 334 b2.Extra = []byte("foo") 335 block.AddUncle(b2) 336 b3 := block.PrevBlock(2).Header() 337 b3.Extra = []byte("foo") 338 block.AddUncle(b3) 339 } 340 } 341 // Assemble the test environment 342 pm := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil) 343 peer, _ := newTestPeer("peer", protocol, pm, true) 344 defer peer.close() 345 346 // Fetch for now the entire chain db 347 hashes := []common.Hash{} 348 for _, key := range pm.chaindb.(*ethdb.MemDatabase).Keys() { 349 if len(key) == len(common.Hash{}) { 350 hashes = append(hashes, common.BytesToHash(key)) 351 } 352 } 353 p2p.Send(peer.app, 0x0d, hashes) 354 msg, err := peer.app.ReadMsg() 355 if err != nil { 356 t.Fatalf("failed to read node data response: %v", err) 357 } 358 if msg.Code != 0x0e { 359 t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c) 360 } 361 var data [][]byte 362 if err := msg.Decode(&data); err != nil { 363 t.Fatalf("failed to decode response node data: %v", err) 364 } 365 // Verify that all hashes correspond to the requested data, and reconstruct a state tree 366 for i, want := range hashes { 367 if hash := crypto.Keccak256Hash(data[i]); hash != want { 368 t.Errorf("data hash mismatch: have %x, want %x", hash, want) 369 } 370 } 371 statedb, _ := ethdb.NewMemDatabase() 372 for i := 0; i < len(data); i++ { 373 statedb.Put(hashes[i].Bytes(), data[i]) 374 } 375 accounts := []common.Address{testBank, acc1Addr, acc2Addr} 376 for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { 377 trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb)) 378 379 for j, acc := range accounts { 380 state, _ := pm.blockchain.State() 381 bw := state.GetBalance(acc) 382 bh := trie.GetBalance(acc) 383 384 if (bw != nil && bh == nil) || (bw == nil && bh != nil) { 385 t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) 386 } 387 if bw != nil && bh != nil && bw.Cmp(bw) != 0 { 388 t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) 389 } 390 } 391 } 392 } 393 394 // Tests that the transaction receipts can be retrieved based on hashes. 395 func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) } 396 397 func testGetReceipt(t *testing.T, protocol int) { 398 // Define three accounts to simulate transactions with 399 acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 400 acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 401 acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) 402 acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) 403 404 signer := types.HomesteadSigner{} 405 // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test) 406 generator := func(i int, block *core.BlockGen) { 407 switch i { 408 case 0: 409 // In block 1, the test bank sends account #1 some ether. 410 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) 411 block.AddTx(tx) 412 case 1: 413 // In block 2, the test bank sends some more ether to account #1. 414 // acc1Addr passes it on to account #2. 415 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) 416 tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) 417 block.AddTx(tx1) 418 block.AddTx(tx2) 419 case 2: 420 // Block 3 is empty but was mined by account #2. 421 block.SetCoinbase(acc2Addr) 422 block.SetExtra([]byte("yeehaw")) 423 case 3: 424 // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). 425 b2 := block.PrevBlock(1).Header() 426 b2.Extra = []byte("foo") 427 block.AddUncle(b2) 428 b3 := block.PrevBlock(2).Header() 429 b3.Extra = []byte("foo") 430 block.AddUncle(b3) 431 } 432 } 433 // Assemble the test environment 434 pm := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil) 435 peer, _ := newTestPeer("peer", protocol, pm, true) 436 defer peer.close() 437 438 // Collect the hashes to request, and the response to expect 439 hashes, receipts := []common.Hash{}, []types.Receipts{} 440 for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { 441 block := pm.blockchain.GetBlockByNumber(i) 442 443 hashes = append(hashes, block.Hash()) 444 receipts = append(receipts, core.GetBlockReceipts(pm.chaindb, block.Hash(), block.NumberU64())) 445 } 446 // Send the hash request and verify the response 447 p2p.Send(peer.app, 0x0f, hashes) 448 if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil { 449 t.Errorf("receipts mismatch: %v", err) 450 } 451 } 452 453 // Tests that post eth protocol handshake, DAO fork-enabled clients also execute 454 // a DAO "challenge" verifying each others' DAO fork headers to ensure they're on 455 // compatible chains. 456 func TestDAOChallengeNoVsNo(t *testing.T) { testDAOChallenge(t, false, false, false) } 457 func TestDAOChallengeNoVsPro(t *testing.T) { testDAOChallenge(t, false, true, false) } 458 func TestDAOChallengeProVsNo(t *testing.T) { testDAOChallenge(t, true, false, false) } 459 func TestDAOChallengeProVsPro(t *testing.T) { testDAOChallenge(t, true, true, false) } 460 func TestDAOChallengeNoVsTimeout(t *testing.T) { testDAOChallenge(t, false, false, true) } 461 func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) } 462 463 func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) { 464 // Reduce the DAO handshake challenge timeout 465 if timeout { 466 defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout) 467 daoChallengeTimeout = 500 * time.Millisecond 468 } 469 // Create a DAO aware protocol manager 470 var ( 471 evmux = new(event.TypeMux) 472 pow = ethash.NewFaker() 473 db, _ = ethdb.NewMemDatabase() 474 config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} 475 gspec = &core.Genesis{Config: config} 476 genesis = gspec.MustCommit(db) 477 blockchain, _ = core.NewBlockChain(db, config, pow, vm.Config{}) 478 ) 479 pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db) 480 if err != nil { 481 t.Fatalf("failed to start test protocol manager: %v", err) 482 } 483 pm.Start(1000) 484 defer pm.Stop() 485 486 // Connect a new peer and check that we receive the DAO challenge 487 peer, _ := newTestPeer("peer", eth63, pm, true) 488 defer peer.close() 489 490 challenge := &getBlockHeadersData{ 491 Origin: hashOrNumber{Number: config.DAOForkBlock.Uint64()}, 492 Amount: 1, 493 Skip: 0, 494 Reverse: false, 495 } 496 if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil { 497 t.Fatalf("challenge mismatch: %v", err) 498 } 499 // Create a block to reply to the challenge if no timeout is simulated 500 if !timeout { 501 blocks, _ := core.GenerateChain(¶ms.ChainConfig{}, genesis, ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) { 502 if remoteForked { 503 block.SetExtra(params.DAOForkBlockExtra) 504 } 505 }) 506 if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil { 507 t.Fatalf("failed to answer challenge: %v", err) 508 } 509 time.Sleep(100 * time.Millisecond) // Sleep to avoid the verification racing with the drops 510 } else { 511 // Otherwise wait until the test timeout passes 512 time.Sleep(daoChallengeTimeout + 500*time.Millisecond) 513 } 514 // Verify that depending on fork side, the remote peer is maintained or dropped 515 if localForked == remoteForked && !timeout { 516 if peers := pm.peers.Len(); peers != 1 { 517 t.Fatalf("peer count mismatch: have %d, want %d", peers, 1) 518 } 519 } else { 520 if peers := pm.peers.Len(); peers != 0 { 521 t.Fatalf("peer count mismatch: have %d, want %d", peers, 0) 522 } 523 } 524 }