github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/eth/handler_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:37</date> 10 //</624450089225555968> 11 12 13 package eth 14 15 import ( 16 "fmt" 17 "math" 18 "math/big" 19 "math/rand" 20 "testing" 21 "time" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/consensus/ethash" 25 "github.com/ethereum/go-ethereum/core" 26 "github.com/ethereum/go-ethereum/core/state" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/core/vm" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/eth/downloader" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/event" 33 "github.com/ethereum/go-ethereum/p2p" 34 "github.com/ethereum/go-ethereum/params" 35 ) 36 37 //测试协议版本和操作模式是否正确匹配。 38 func TestProtocolCompatibility(t *testing.T) { 39 //定义兼容性图表 40 tests := []struct { 41 version uint 42 mode downloader.SyncMode 43 compatible bool 44 }{ 45 {61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true}, 46 {61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true}, 47 } 48 //确保我们搞砸的东西都恢复了 49 backup := ProtocolVersions 50 defer func() { ProtocolVersions = backup }() 51 52 //尝试所有可用的兼容性配置并检查错误 53 for i, tt := range tests { 54 ProtocolVersions = []uint{tt.version} 55 56 pm, _, err := newTestProtocolManager(tt.mode, 0, nil, nil) 57 if pm != nil { 58 defer pm.Stop() 59 } 60 if (err == nil && !tt.compatible) || (err != nil && tt.compatible) { 61 t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible) 62 } 63 } 64 } 65 66 //可以根据用户查询从远程链中检索阻止头的测试。 67 func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) } 68 func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) } 69 70 func testGetBlockHeaders(t *testing.T, protocol int) { 71 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil) 72 peer, _ := newTestPeer("peer", protocol, pm, true) 73 defer peer.close() 74 75 //为测试创建一个“随机”的未知哈希 76 var unknown common.Hash 77 for i := range unknown { 78 unknown[i] = byte(i) 79 } 80 //为各种方案创建一批测试 81 limit := uint64(downloader.MaxHeaderFetch) 82 tests := []struct { 83 query *getBlockHeadersData //要为头检索执行的查询 84 expect []common.Hash //应为其头的块的哈希 85 }{ 86 //单个随机块也应该可以通过哈希和数字检索。 87 { 88 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1}, 89 []common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, 90 }, { 91 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1}, 92 []common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, 93 }, 94 //应可从两个方向检索多个邮件头 95 { 96 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3}, 97 []common.Hash{ 98 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 99 pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(), 100 pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(), 101 }, 102 }, { 103 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true}, 104 []common.Hash{ 105 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 106 pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(), 107 pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(), 108 }, 109 }, 110 //应检索具有跳过列表的多个邮件头 111 { 112 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3}, 113 []common.Hash{ 114 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 115 pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(), 116 pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(), 117 }, 118 }, { 119 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true}, 120 []common.Hash{ 121 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 122 pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(), 123 pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(), 124 }, 125 }, 126 //链端点应该是可检索的 127 { 128 &getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, 129 []common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()}, 130 }, { 131 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1}, 132 []common.Hash{pm.blockchain.CurrentBlock().Hash()}, 133 }, 134 //确保遵守协议限制 135 { 136 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, 137 pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit), 138 }, 139 //检查请求是否处理得当 140 { 141 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, 142 []common.Hash{ 143 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), 144 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(), 145 }, 146 }, { 147 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, 148 []common.Hash{ 149 pm.blockchain.GetBlockByNumber(4).Hash(), 150 pm.blockchain.GetBlockByNumber(0).Hash(), 151 }, 152 }, 153 //检查请求是否处理得当,即使中间跳过 154 { 155 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, 156 []common.Hash{ 157 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), 158 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(), 159 }, 160 }, { 161 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, 162 []common.Hash{ 163 pm.blockchain.GetBlockByNumber(4).Hash(), 164 pm.blockchain.GetBlockByNumber(1).Hash(), 165 }, 166 }, 167 //检查一个角情况,在这种情况下,请求更多可以迭代通过端点 168 { 169 &getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true}, 170 []common.Hash{ 171 pm.blockchain.GetBlockByNumber(2).Hash(), 172 pm.blockchain.GetBlockByNumber(1).Hash(), 173 pm.blockchain.GetBlockByNumber(0).Hash(), 174 }, 175 }, 176 //检查将溢出循环跳回到链起始处的角情况 177 { 178 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1}, 179 []common.Hash{ 180 pm.blockchain.GetBlockByNumber(3).Hash(), 181 }, 182 }, 183 //检查跳过溢出循环返回同一头的角情况 184 { 185 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64}, 186 []common.Hash{ 187 pm.blockchain.GetBlockByNumber(1).Hash(), 188 }, 189 }, 190 //检查是否未返回不存在的邮件头 191 { 192 &getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, 193 []common.Hash{}, 194 }, { 195 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1}, 196 []common.Hash{}, 197 }, 198 } 199 //运行每个测试并对照链验证结果 200 for i, tt := range tests { 201 //收集响应中预期的头 202 headers := []*types.Header{} 203 for _, hash := range tt.expect { 204 headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header()) 205 } 206 //发送哈希请求并验证响应 207 p2p.Send(peer.app, 0x03, tt.query) 208 if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil { 209 t.Errorf("test %d: headers mismatch: %v", i, err) 210 } 211 //如果测试使用的是数字源,也可以使用哈希进行重复。 212 if tt.query.Origin.Hash == (common.Hash{}) { 213 if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil { 214 tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0 215 216 p2p.Send(peer.app, 0x03, tt.query) 217 if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil { 218 t.Errorf("test %d: headers mismatch: %v", i, err) 219 } 220 } 221 } 222 } 223 } 224 225 //可以基于哈希从远程链中检索阻止内容的测试。 226 func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) } 227 func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) } 228 229 func testGetBlockBodies(t *testing.T, protocol int) { 230 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil) 231 peer, _ := newTestPeer("peer", protocol, pm, true) 232 defer peer.close() 233 234 //为各种方案创建一批测试 235 limit := downloader.MaxBlockFetch 236 tests := []struct { 237 random int //从链中随机提取的块数 238 explicit []common.Hash //显式请求的块 239 available []bool //显式请求块的可用性 240 expected int //期望的现有块总数 241 }{ 242 {1, nil, nil, 1}, //单个随机块应该是可检索的 243 {10, nil, nil, 10}, //应可检索多个随机块 244 {limit, nil, nil, limit}, //最大可能的块应该是可检索的 245 {limit + 1, nil, nil, limit}, //不应返回超过可能的块计数 246 {0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, //Genesis区块应该是可回收的。 247 {0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, //链头滑轮应可回收。 248 {0, []common.Hash{{}}, []bool{false}, 0}, //不应返回不存在的块 249 250 //现有和不存在的块交错不应导致问题 251 {0, []common.Hash{ 252 {}, 253 pm.blockchain.GetBlockByNumber(1).Hash(), 254 {}, 255 pm.blockchain.GetBlockByNumber(10).Hash(), 256 {}, 257 pm.blockchain.GetBlockByNumber(100).Hash(), 258 {}, 259 }, []bool{false, true, false, true, false, true, false}, 3}, 260 } 261 //运行每个测试并对照链验证结果 262 for i, tt := range tests { 263 //收集要请求的哈希值和预期的响应 264 hashes, seen := []common.Hash{}, make(map[int64]bool) 265 bodies := []*blockBody{} 266 267 for j := 0; j < tt.random; j++ { 268 for { 269 num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64())) 270 if !seen[num] { 271 seen[num] = true 272 273 block := pm.blockchain.GetBlockByNumber(uint64(num)) 274 hashes = append(hashes, block.Hash()) 275 if len(bodies) < tt.expected { 276 bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) 277 } 278 break 279 } 280 } 281 } 282 for j, hash := range tt.explicit { 283 hashes = append(hashes, hash) 284 if tt.available[j] && len(bodies) < tt.expected { 285 block := pm.blockchain.GetBlockByHash(hash) 286 bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) 287 } 288 } 289 //发送哈希请求并验证响应 290 p2p.Send(peer.app, 0x05, hashes) 291 if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil { 292 t.Errorf("test %d: bodies mismatch: %v", i, err) 293 } 294 } 295 } 296 297 //测试可以基于哈希检索节点状态数据库。 298 func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) } 299 300 func testGetNodeData(t *testing.T, protocol int) { 301 //定义三个科目以模拟交易 302 acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 303 acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 304 acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) 305 acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) 306 307 signer := types.HomesteadSigner{} 308 //用一些简单的事务创建一个链生成器(公然从@fjl/chain_markets_test中被盗) 309 generator := func(i int, block *core.BlockGen) { 310 switch i { 311 case 0: 312 //在块1中,测试银行发送帐户1一些乙醚。 313 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) 314 block.AddTx(tx) 315 case 1: 316 //在区块2中,测试银行向账户1发送更多乙醚。 317 //acc1addr将其传递到account_2。 318 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) 319 tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) 320 block.AddTx(tx1) 321 block.AddTx(tx2) 322 case 2: 323 //区块3为空,但由账户2开采。 324 block.SetCoinbase(acc2Addr) 325 block.SetExtra([]byte("yeehaw")) 326 case 3: 327 //块4包括块2和3作为叔叔头(带有修改的额外数据)。 328 b2 := block.PrevBlock(1).Header() 329 b2.Extra = []byte("foo") 330 block.AddUncle(b2) 331 b3 := block.PrevBlock(2).Header() 332 b3.Extra = []byte("foo") 333 block.AddUncle(b3) 334 } 335 } 336 //组装测试环境 337 pm, db := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil) 338 peer, _ := newTestPeer("peer", protocol, pm, true) 339 defer peer.close() 340 341 //现在获取整个链数据库 342 hashes := []common.Hash{} 343 for _, key := range db.Keys() { 344 if len(key) == len(common.Hash{}) { 345 hashes = append(hashes, common.BytesToHash(key)) 346 } 347 } 348 p2p.Send(peer.app, 0x0d, hashes) 349 msg, err := peer.app.ReadMsg() 350 if err != nil { 351 t.Fatalf("failed to read node data response: %v", err) 352 } 353 if msg.Code != 0x0e { 354 t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c) 355 } 356 var data [][]byte 357 if err := msg.Decode(&data); err != nil { 358 t.Fatalf("failed to decode response node data: %v", err) 359 } 360 //验证所有哈希是否与请求的数据对应,并重建状态树 361 for i, want := range hashes { 362 if hash := crypto.Keccak256Hash(data[i]); hash != want { 363 t.Errorf("data hash mismatch: have %x, want %x", hash, want) 364 } 365 } 366 statedb := ethdb.NewMemDatabase() 367 for i := 0; i < len(data); i++ { 368 statedb.Put(hashes[i].Bytes(), data[i]) 369 } 370 accounts := []common.Address{testBank, acc1Addr, acc2Addr} 371 for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { 372 trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb)) 373 374 for j, acc := range accounts { 375 state, _ := pm.blockchain.State() 376 bw := state.GetBalance(acc) 377 bh := trie.GetBalance(acc) 378 379 if (bw != nil && bh == nil) || (bw == nil && bh != nil) { 380 t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) 381 } 382 if bw != nil && bh != nil && bw.Cmp(bw) != 0 { 383 t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) 384 } 385 } 386 } 387 } 388 389 //测试是否可以基于哈希值检索事务回执。 390 func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) } 391 392 func testGetReceipt(t *testing.T, protocol int) { 393 //定义三个科目以模拟交易 394 acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 395 acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 396 acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) 397 acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) 398 399 signer := types.HomesteadSigner{} 400 //用一些简单的事务创建一个链生成器(公然从@fjl/chain_markets_test中被盗) 401 generator := func(i int, block *core.BlockGen) { 402 switch i { 403 case 0: 404 //在块1中,测试银行发送帐户1一些乙醚。 405 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) 406 block.AddTx(tx) 407 case 1: 408 //在区块2中,测试银行向账户1发送更多乙醚。 409 //acc1addr将其传递到account_2。 410 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) 411 tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) 412 block.AddTx(tx1) 413 block.AddTx(tx2) 414 case 2: 415 //区块3为空,但由账户2开采。 416 block.SetCoinbase(acc2Addr) 417 block.SetExtra([]byte("yeehaw")) 418 case 3: 419 //块4包括块2和3作为叔叔头(带有修改的额外数据)。 420 b2 := block.PrevBlock(1).Header() 421 b2.Extra = []byte("foo") 422 block.AddUncle(b2) 423 b3 := block.PrevBlock(2).Header() 424 b3.Extra = []byte("foo") 425 block.AddUncle(b3) 426 } 427 } 428 //组装测试环境 429 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil) 430 peer, _ := newTestPeer("peer", protocol, pm, true) 431 defer peer.close() 432 433 //收集要请求的哈希值和预期的响应 434 hashes, receipts := []common.Hash{}, []types.Receipts{} 435 for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { 436 block := pm.blockchain.GetBlockByNumber(i) 437 438 hashes = append(hashes, block.Hash()) 439 receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash())) 440 } 441 //发送哈希请求并验证响应 442 p2p.Send(peer.app, 0x0f, hashes) 443 if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil { 444 t.Errorf("receipts mismatch: %v", err) 445 } 446 } 447 448 //发布ETH协议握手的测试,启用DAO分叉的客户端也会执行 449 //一个DAO“挑战”验证彼此的DAO分叉头,以确保它们处于打开状态 450 //兼容的链条。 451 func TestDAOChallengeNoVsNo(t *testing.T) { testDAOChallenge(t, false, false, false) } 452 func TestDAOChallengeNoVsPro(t *testing.T) { testDAOChallenge(t, false, true, false) } 453 func TestDAOChallengeProVsNo(t *testing.T) { testDAOChallenge(t, true, false, false) } 454 func TestDAOChallengeProVsPro(t *testing.T) { testDAOChallenge(t, true, true, false) } 455 func TestDAOChallengeNoVsTimeout(t *testing.T) { testDAOChallenge(t, false, false, true) } 456 func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) } 457 458 func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) { 459 //减少DAO握手挑战超时 460 if timeout { 461 defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout) 462 daoChallengeTimeout = 500 * time.Millisecond 463 } 464 //创建DAO感知协议管理器 465 var ( 466 evmux = new(event.TypeMux) 467 pow = ethash.NewFaker() 468 db = ethdb.NewMemDatabase() 469 config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} 470 gspec = &core.Genesis{Config: config} 471 genesis = gspec.MustCommit(db) 472 ) 473 blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil) 474 if err != nil { 475 t.Fatalf("failed to create new blockchain: %v", err) 476 } 477 pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil) 478 if err != nil { 479 t.Fatalf("failed to start test protocol manager: %v", err) 480 } 481 pm.Start(1000) 482 defer pm.Stop() 483 484 //连接新的对等点并检查我们是否收到DAO挑战 485 peer, _ := newTestPeer("peer", eth63, pm, true) 486 defer peer.close() 487 488 challenge := &getBlockHeadersData{ 489 Origin: hashOrNumber{Number: config.DAOForkBlock.Uint64()}, 490 Amount: 1, 491 Skip: 0, 492 Reverse: false, 493 } 494 if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil { 495 t.Fatalf("challenge mismatch: %v", err) 496 } 497 //如果没有模拟超时,则创建一个块以答复质询 498 if !timeout { 499 blocks, _ := core.GenerateChain(¶ms.ChainConfig{}, genesis, ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) { 500 if remoteForked { 501 block.SetExtra(params.DAOForkBlockExtra) 502 } 503 }) 504 if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil { 505 t.Fatalf("failed to answer challenge: %v", err) 506 } 507 time.Sleep(100 * time.Millisecond) //睡眠以避免验证与水滴赛跑 508 } else { 509 //否则,等待测试超时通过 510 time.Sleep(daoChallengeTimeout + 500*time.Millisecond) 511 } 512 //验证是否根据分叉端维护或删除远程对等机 513 if localForked == remoteForked && !timeout { 514 if peers := pm.peers.Len(); peers != 1 { 515 t.Fatalf("peer count mismatch: have %d, want %d", peers, 1) 516 } 517 } else { 518 if peers := pm.peers.Len(); peers != 0 { 519 t.Fatalf("peer count mismatch: have %d, want %d", peers, 0) 520 } 521 } 522 } 523 524 func TestBroadcastBlock(t *testing.T) { 525 var tests = []struct { 526 totalPeers int 527 broadcastExpected int 528 }{ 529 {1, 1}, 530 {2, 2}, 531 {3, 3}, 532 {4, 4}, 533 {5, 4}, 534 {9, 4}, 535 {12, 4}, 536 {16, 4}, 537 {26, 5}, 538 {100, 10}, 539 } 540 for _, test := range tests { 541 testBroadcastBlock(t, test.totalPeers, test.broadcastExpected) 542 } 543 } 544 545 func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) { 546 var ( 547 evmux = new(event.TypeMux) 548 pow = ethash.NewFaker() 549 db = ethdb.NewMemDatabase() 550 config = ¶ms.ChainConfig{} 551 gspec = &core.Genesis{Config: config} 552 genesis = gspec.MustCommit(db) 553 ) 554 blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil) 555 if err != nil { 556 t.Fatalf("failed to create new blockchain: %v", err) 557 } 558 pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil) 559 if err != nil { 560 t.Fatalf("failed to start test protocol manager: %v", err) 561 } 562 pm.Start(1000) 563 defer pm.Stop() 564 var peers []*testPeer 565 for i := 0; i < totalPeers; i++ { 566 peer, _ := newTestPeer(fmt.Sprintf("peer %d", i), eth63, pm, true) 567 defer peer.close() 568 peers = append(peers, peer) 569 } 570 chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) {}) 571 /*广播块(链[0],真/*传播*/) 572 573 错误:=make(chan错误,totalpeers) 574 Donech:=制造(Chan结构,totalpeers) 575 对于u,对等:=范围对等 576 Go func(P*testpeer) 577 如果错误:=p2p.expectmsg(p.app,newblockmsg,&newblockdata block:chain[0],td:big.newint(131136));错误!= nIL{ 578 埃尔奇-厄尔 579 }否则{ 580 Donech<-结构 581 } 582 }(对等体) 583 } 584 超时:=time.after(300*time.millisecond) 585 var接收计数int 586 外部: 587 对于{ 588 选择{ 589 案例错误=<-错误: 590 打破外部 591 案例:DONECH: 592 接收计数+ 593 如果receivedCount==totalPeers 594 打破外部 595 } 596 案例<超时: 597 打破外部 598 } 599 } 600 对于u,对等:=范围对等 601 peer.app.close()。 602 } 603 如果犯错!= nIL{ 604 t.errorf(“按对等方匹配块时出错:%v”,err) 605 } 606 如果收到账单!=需要广播 607 t.errorf(“块广播到%d个对等方,应为%d”,ReceivedCount,应为BroadcastExpected) 608 } 609 } 610