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