github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/fetcher/fetcher_test.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2015 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package fetcher 26 27 import ( 28 "errors" 29 "math/big" 30 "sync" 31 "sync/atomic" 32 "testing" 33 "time" 34 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/consensus/ethash" 37 "github.com/ethereum/go-ethereum/core" 38 "github.com/ethereum/go-ethereum/core/types" 39 "github.com/ethereum/go-ethereum/crypto" 40 "github.com/ethereum/go-ethereum/ethdb" 41 "github.com/ethereum/go-ethereum/params" 42 ) 43 44 var ( 45 testdb = ethdb.NewMemDatabase() 46 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 47 testAddress = crypto.PubkeyToAddress(testKey.PublicKey) 48 genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) 49 unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit}, nil, nil, nil) 50 ) 51 52 //makechain创建一个由n个块组成的链,从父块开始并包含父块。 53 //返回的哈希链是有序的head->parent。此外,每三个街区 54 //包含一个事务,每隔5分钟一个叔叔以允许测试正确的块 55 //重新组装。 56 func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { 57 blocks, _ := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testdb, n, func(i int, block *core.BlockGen) { 58 block.SetCoinbase(common.Address{seed}) 59 60 //如果区块号是3的倍数,则向矿工发送奖金交易。 61 if parent == genesis && i%3 == 0 { 62 signer := types.MakeSigner(params.TestChainConfig, block.Number()) 63 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) 64 if err != nil { 65 panic(err) 66 } 67 block.AddTx(tx) 68 } 69 //如果区块编号是5的倍数,请在区块中添加一个奖金叔叔。 70 if i%5 == 0 { 71 block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) 72 } 73 }) 74 hashes := make([]common.Hash, n+1) 75 hashes[len(hashes)-1] = parent.Hash() 76 blockm := make(map[common.Hash]*types.Block, n+1) 77 blockm[parent.Hash()] = parent 78 for i, b := range blocks { 79 hashes[len(hashes)-i-2] = b.Hash() 80 blockm[b.Hash()] = b 81 } 82 return hashes, blockm 83 } 84 85 //Fetchertester是模拟本地块链的测试模拟器。 86 type fetcherTester struct { 87 fetcher *Fetcher 88 89 hashes []common.Hash //属于测试人员的哈希链 90 blocks map[common.Hash]*types.Block //属于测试仪的块 91 drops map[string]bool //取方丢弃的对等点图 92 93 lock sync.RWMutex 94 } 95 96 //NewTester创建一个新的获取器测试mocker。 97 func newTester() *fetcherTester { 98 tester := &fetcherTester{ 99 hashes: []common.Hash{genesis.Hash()}, 100 blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, 101 drops: make(map[string]bool), 102 } 103 tester.fetcher = New(tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer) 104 tester.fetcher.Start() 105 106 return tester 107 } 108 109 //GetBlock从测试仪的区块链中检索一个区块。 110 func (f *fetcherTester) getBlock(hash common.Hash) *types.Block { 111 f.lock.RLock() 112 defer f.lock.RUnlock() 113 114 return f.blocks[hash] 115 } 116 117 //verifyheader是块头验证的nop占位符。 118 func (f *fetcherTester) verifyHeader(header *types.Header) error { 119 return nil 120 } 121 122 //BroadcastBlock是块广播的NOP占位符。 123 func (f *fetcherTester) broadcastBlock(block *types.Block, propagate bool) { 124 } 125 126 //chain height检索链的当前高度(块号)。 127 func (f *fetcherTester) chainHeight() uint64 { 128 f.lock.RLock() 129 defer f.lock.RUnlock() 130 131 return f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() 132 } 133 134 //insertchain向模拟链中注入新的块。 135 func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) { 136 f.lock.Lock() 137 defer f.lock.Unlock() 138 139 for i, block := range blocks { 140 //确保中的父级 141 if _, ok := f.blocks[block.ParentHash()]; !ok { 142 return i, errors.New("unknown parent") 143 } 144 //如果已经存在相同高度,则丢弃所有新块 145 if block.NumberU64() <= f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() { 146 return i, nil 147 } 148 //否则就建立我们现在的链条 149 f.hashes = append(f.hashes, block.Hash()) 150 f.blocks[block.Hash()] = block 151 } 152 return 0, nil 153 } 154 155 //Droppeer是一个对等删除的仿真器,只需将 156 //同龄人被牵线人甩了。 157 func (f *fetcherTester) dropPeer(peer string) { 158 f.lock.Lock() 159 defer f.lock.Unlock() 160 161 f.drops[peer] = true 162 } 163 164 //MakeHeaderFetcher检索与模拟对等机关联的块头获取程序。 165 func (f *fetcherTester) makeHeaderFetcher(peer string, blocks map[common.Hash]*types.Block, drift time.Duration) headerRequesterFn { 166 closure := make(map[common.Hash]*types.Block) 167 for hash, block := range blocks { 168 closure[hash] = block 169 } 170 //创建一个从闭包返回头的函数 171 return func(hash common.Hash) error { 172 //收集积木返回 173 headers := make([]*types.Header, 0, 1) 174 if block, ok := closure[hash]; ok { 175 headers = append(headers, block.Header()) 176 } 177 //返回新线程 178 go f.fetcher.FilterHeaders(peer, headers, time.Now().Add(drift)) 179 180 return nil 181 } 182 } 183 184 //MakeBodyFetcher检索与模拟对等体关联的块体Fetcher。 185 func (f *fetcherTester) makeBodyFetcher(peer string, blocks map[common.Hash]*types.Block, drift time.Duration) bodyRequesterFn { 186 closure := make(map[common.Hash]*types.Block) 187 for hash, block := range blocks { 188 closure[hash] = block 189 } 190 //创建从闭包返回块的函数 191 return func(hashes []common.Hash) error { 192 //收集块体返回 193 transactions := make([][]*types.Transaction, 0, len(hashes)) 194 uncles := make([][]*types.Header, 0, len(hashes)) 195 196 for _, hash := range hashes { 197 if block, ok := closure[hash]; ok { 198 transactions = append(transactions, block.Transactions()) 199 uncles = append(uncles, block.Uncles()) 200 } 201 } 202 //返回新线程 203 go f.fetcher.FilterBodies(peer, transactions, uncles, time.Now().Add(drift)) 204 205 return nil 206 } 207 } 208 209 //VerifyFetchingEvent验证单个事件是否到达提取通道。 210 func verifyFetchingEvent(t *testing.T, fetching chan []common.Hash, arrive bool) { 211 if arrive { 212 select { 213 case <-fetching: 214 case <-time.After(time.Second): 215 t.Fatalf("fetching timeout") 216 } 217 } else { 218 select { 219 case <-fetching: 220 t.Fatalf("fetching invoked") 221 case <-time.After(10 * time.Millisecond): 222 } 223 } 224 } 225 226 //VerifyCompletingEvent验证单个事件是否到达完成通道。 227 func verifyCompletingEvent(t *testing.T, completing chan []common.Hash, arrive bool) { 228 if arrive { 229 select { 230 case <-completing: 231 case <-time.After(time.Second): 232 t.Fatalf("completing timeout") 233 } 234 } else { 235 select { 236 case <-completing: 237 t.Fatalf("completing invoked") 238 case <-time.After(10 * time.Millisecond): 239 } 240 } 241 } 242 243 //verifyimportevent验证一个事件是否到达导入通道。 244 func verifyImportEvent(t *testing.T, imported chan *types.Block, arrive bool) { 245 if arrive { 246 select { 247 case <-imported: 248 case <-time.After(time.Second): 249 t.Fatalf("import timeout") 250 } 251 } else { 252 select { 253 case <-imported: 254 t.Fatalf("import invoked") 255 case <-time.After(10 * time.Millisecond): 256 } 257 } 258 } 259 260 //verifyimportcount验证在 261 //导入挂钩通道。 262 func verifyImportCount(t *testing.T, imported chan *types.Block, count int) { 263 for i := 0; i < count; i++ { 264 select { 265 case <-imported: 266 case <-time.After(time.Second): 267 t.Fatalf("block %d: import timeout", i+1) 268 } 269 } 270 verifyImportDone(t, imported) 271 } 272 273 //verifyimportdone验证导入通道上没有其他事件到达。 274 func verifyImportDone(t *testing.T, imported chan *types.Block) { 275 select { 276 case <-imported: 277 t.Fatalf("extra block imported") 278 case <-time.After(50 * time.Millisecond): 279 } 280 } 281 282 //测试获取程序接受块通知并为 283 //成功导入到本地链。 284 func TestSequentialAnnouncements62(t *testing.T) { testSequentialAnnouncements(t, 62) } 285 func TestSequentialAnnouncements63(t *testing.T) { testSequentialAnnouncements(t, 63) } 286 func TestSequentialAnnouncements64(t *testing.T) { testSequentialAnnouncements(t, 64) } 287 288 func testSequentialAnnouncements(t *testing.T, protocol int) { 289 //创建要导入的块链 290 targetBlocks := 4 * hashLimit 291 hashes, blocks := makeChain(targetBlocks, 0, genesis) 292 293 tester := newTester() 294 headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 295 bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 296 297 //迭代地通知块,直到全部导入 298 imported := make(chan *types.Block) 299 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 300 301 for i := len(hashes) - 2; i >= 0; i-- { 302 tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 303 verifyImportEvent(t, imported, true) 304 } 305 verifyImportDone(t, imported) 306 } 307 308 //测试多个对等方(甚至同一个bug)是否宣布块 309 //它们最多只能下载一次。 310 func TestConcurrentAnnouncements62(t *testing.T) { testConcurrentAnnouncements(t, 62) } 311 func TestConcurrentAnnouncements63(t *testing.T) { testConcurrentAnnouncements(t, 63) } 312 func TestConcurrentAnnouncements64(t *testing.T) { testConcurrentAnnouncements(t, 64) } 313 314 func testConcurrentAnnouncements(t *testing.T, protocol int) { 315 //创建要导入的块链 316 targetBlocks := 4 * hashLimit 317 hashes, blocks := makeChain(targetBlocks, 0, genesis) 318 319 //为请求装配带有内置计数器的测试仪 320 tester := newTester() 321 firstHeaderFetcher := tester.makeHeaderFetcher("first", blocks, -gatherSlack) 322 firstBodyFetcher := tester.makeBodyFetcher("first", blocks, 0) 323 secondHeaderFetcher := tester.makeHeaderFetcher("second", blocks, -gatherSlack) 324 secondBodyFetcher := tester.makeBodyFetcher("second", blocks, 0) 325 326 counter := uint32(0) 327 firstHeaderWrapper := func(hash common.Hash) error { 328 atomic.AddUint32(&counter, 1) 329 return firstHeaderFetcher(hash) 330 } 331 secondHeaderWrapper := func(hash common.Hash) error { 332 atomic.AddUint32(&counter, 1) 333 return secondHeaderFetcher(hash) 334 } 335 //迭代地通知块,直到全部导入 336 imported := make(chan *types.Block) 337 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 338 339 for i := len(hashes) - 2; i >= 0; i-- { 340 tester.fetcher.Notify("first", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), firstHeaderWrapper, firstBodyFetcher) 341 tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout+time.Millisecond), secondHeaderWrapper, secondBodyFetcher) 342 tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout-time.Millisecond), secondHeaderWrapper, secondBodyFetcher) 343 verifyImportEvent(t, imported, true) 344 } 345 verifyImportDone(t, imported) 346 347 //确保两次未检索到任何块 348 if int(counter) != targetBlocks { 349 t.Fatalf("retrieval count mismatch: have %v, want %v", counter, targetBlocks) 350 } 351 } 352 353 //在提取前一个通知时通知到达的测试 354 //导致有效导入。 355 func TestOverlappingAnnouncements62(t *testing.T) { testOverlappingAnnouncements(t, 62) } 356 func TestOverlappingAnnouncements63(t *testing.T) { testOverlappingAnnouncements(t, 63) } 357 func TestOverlappingAnnouncements64(t *testing.T) { testOverlappingAnnouncements(t, 64) } 358 359 func testOverlappingAnnouncements(t *testing.T, protocol int) { 360 //创建要导入的块链 361 targetBlocks := 4 * hashLimit 362 hashes, blocks := makeChain(targetBlocks, 0, genesis) 363 364 tester := newTester() 365 headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 366 bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 367 368 //迭代地通知块,但连续地重叠它们 369 overlap := 16 370 imported := make(chan *types.Block, len(hashes)-1) 371 for i := 0; i < overlap; i++ { 372 imported <- nil 373 } 374 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 375 376 for i := len(hashes) - 2; i >= 0; i-- { 377 tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 378 select { 379 case <-imported: 380 case <-time.After(time.Second): 381 t.Fatalf("block %d: import timeout", len(hashes)-i) 382 } 383 } 384 //等待所有导入完成并检查计数 385 verifyImportCount(t, imported, overlap) 386 } 387 388 //宣布已检索的测试将不会重复。 389 func TestPendingDeduplication62(t *testing.T) { testPendingDeduplication(t, 62) } 390 func TestPendingDeduplication63(t *testing.T) { testPendingDeduplication(t, 63) } 391 func TestPendingDeduplication64(t *testing.T) { testPendingDeduplication(t, 64) } 392 393 func testPendingDeduplication(t *testing.T, protocol int) { 394 //创建哈希和相应的块 395 hashes, blocks := makeChain(1, 0, genesis) 396 397 //用内置计数器和延迟回卷器组装测试仪 398 tester := newTester() 399 headerFetcher := tester.makeHeaderFetcher("repeater", blocks, -gatherSlack) 400 bodyFetcher := tester.makeBodyFetcher("repeater", blocks, 0) 401 402 delay := 50 * time.Millisecond 403 counter := uint32(0) 404 headerWrapper := func(hash common.Hash) error { 405 atomic.AddUint32(&counter, 1) 406 407 //模拟长时间运行的获取 408 go func() { 409 time.Sleep(delay) 410 headerFetcher(hash) 411 }() 412 return nil 413 } 414 //多次通知同一个块,直到它被提取(等待任何挂起的操作) 415 for tester.getBlock(hashes[0]) == nil { 416 tester.fetcher.Notify("repeater", hashes[0], 1, time.Now().Add(-arriveTimeout), headerWrapper, bodyFetcher) 417 time.Sleep(time.Millisecond) 418 } 419 time.Sleep(delay) 420 421 //检查是否已导入所有块,并且未提取两次 422 if imported := len(tester.blocks); imported != 2 { 423 t.Fatalf("synchronised block mismatch: have %v, want %v", imported, 2) 424 } 425 if int(counter) != 1 { 426 t.Fatalf("retrieval count mismatch: have %v, want %v", counter, 1) 427 } 428 } 429 430 //以随机顺序检索公告的测试将被缓存,并最终 431 //填充所有间隙时导入。 432 func TestRandomArrivalImport62(t *testing.T) { testRandomArrivalImport(t, 62) } 433 func TestRandomArrivalImport63(t *testing.T) { testRandomArrivalImport(t, 63) } 434 func TestRandomArrivalImport64(t *testing.T) { testRandomArrivalImport(t, 64) } 435 436 func testRandomArrivalImport(t *testing.T, protocol int) { 437 //创建要导入的块链,然后选择一个要延迟的块链 438 targetBlocks := maxQueueDist 439 hashes, blocks := makeChain(targetBlocks, 0, genesis) 440 skip := targetBlocks / 2 441 442 tester := newTester() 443 headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 444 bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 445 446 //迭代地通知块,跳过一个条目 447 imported := make(chan *types.Block, len(hashes)-1) 448 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 449 450 for i := len(hashes) - 1; i >= 0; i-- { 451 if i != skip { 452 tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 453 time.Sleep(time.Millisecond) 454 } 455 } 456 //最后宣布跳过的条目并检查完全导入 457 tester.fetcher.Notify("valid", hashes[skip], uint64(len(hashes)-skip-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 458 verifyImportCount(t, imported, len(hashes)-1) 459 } 460 461 //引导块排队的测试(由于块传播与哈希公告) 462 //正确安排、填充和导入队列间隙。 463 func TestQueueGapFill62(t *testing.T) { testQueueGapFill(t, 62) } 464 func TestQueueGapFill63(t *testing.T) { testQueueGapFill(t, 63) } 465 func TestQueueGapFill64(t *testing.T) { testQueueGapFill(t, 64) } 466 467 func testQueueGapFill(t *testing.T, protocol int) { 468 //创建一个要导入的块链,并选择一个完全不公告的块链 469 targetBlocks := maxQueueDist 470 hashes, blocks := makeChain(targetBlocks, 0, genesis) 471 skip := targetBlocks / 2 472 473 tester := newTester() 474 headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 475 bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 476 477 //迭代地通知块,跳过一个条目 478 imported := make(chan *types.Block, len(hashes)-1) 479 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 480 481 for i := len(hashes) - 1; i >= 0; i-- { 482 if i != skip { 483 tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 484 time.Sleep(time.Millisecond) 485 } 486 } 487 //直接填充缺失的块,就像传播一样 488 tester.fetcher.Enqueue("valid", blocks[hashes[skip]]) 489 verifyImportCount(t, imported, len(hashes)-1) 490 } 491 492 //阻止来自不同源(多个传播、哈希)的测试 493 //不安排多次导入。 494 func TestImportDeduplication62(t *testing.T) { testImportDeduplication(t, 62) } 495 func TestImportDeduplication63(t *testing.T) { testImportDeduplication(t, 63) } 496 func TestImportDeduplication64(t *testing.T) { testImportDeduplication(t, 64) } 497 498 func testImportDeduplication(t *testing.T, protocol int) { 499 //创建两个要导入的块(一个用于复制,另一个用于暂停) 500 hashes, blocks := makeChain(2, 0, genesis) 501 502 //创建检测仪并用计数器包装进口商 503 tester := newTester() 504 headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 505 bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 506 507 counter := uint32(0) 508 tester.fetcher.insertChain = func(blocks types.Blocks) (int, error) { 509 atomic.AddUint32(&counter, uint32(len(blocks))) 510 return tester.insertChain(blocks) 511 } 512 //检测获取和导入的事件 513 fetching := make(chan []common.Hash) 514 imported := make(chan *types.Block, len(hashes)-1) 515 tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- hashes } 516 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 517 518 //通知复制块,等待检索,并直接传播 519 tester.fetcher.Notify("valid", hashes[0], 1, time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 520 <-fetching 521 522 tester.fetcher.Enqueue("valid", blocks[hashes[0]]) 523 tester.fetcher.Enqueue("valid", blocks[hashes[0]]) 524 tester.fetcher.Enqueue("valid", blocks[hashes[0]]) 525 526 //像传播一样直接填充缺失的块,并检查导入的唯一性 527 tester.fetcher.Enqueue("valid", blocks[hashes[1]]) 528 verifyImportCount(t, imported, 2) 529 530 if counter != 2 { 531 t.Fatalf("import invocation count mismatch: have %v, want %v", counter, 2) 532 } 533 } 534 535 //用远低于或高于当前磁头的数字阻塞的测试得到 536 //丢弃以防止将资源浪费在来自故障对等机的无用块上。 537 func TestDistantPropagationDiscarding(t *testing.T) { 538 //创建一个长链以导入和定义丢弃边界 539 hashes, blocks := makeChain(3*maxQueueDist, 0, genesis) 540 head := hashes[len(hashes)/2] 541 542 low, high := len(hashes)/2+maxUncleDist+1, len(hashes)/2-maxQueueDist-1 543 544 //创建一个测试仪并模拟上边链中间的头块 545 tester := newTester() 546 547 tester.lock.Lock() 548 tester.hashes = []common.Hash{head} 549 tester.blocks = map[common.Hash]*types.Block{head: blocks[head]} 550 tester.lock.Unlock() 551 552 //确保丢弃数字低于阈值的块 553 tester.fetcher.Enqueue("lower", blocks[hashes[low]]) 554 time.Sleep(10 * time.Millisecond) 555 if !tester.fetcher.queue.Empty() { 556 t.Fatalf("fetcher queued stale block") 557 } 558 //确保丢弃数字高于阈值的块 559 tester.fetcher.Enqueue("higher", blocks[hashes[high]]) 560 time.Sleep(10 * time.Millisecond) 561 if !tester.fetcher.queue.Empty() { 562 t.Fatalf("fetcher queued future block") 563 } 564 } 565 566 //数字远低于或高于输出电流的测试 567 //头被丢弃,以防止浪费资源在无用的块故障 568 //同龄人。 569 func TestDistantAnnouncementDiscarding62(t *testing.T) { testDistantAnnouncementDiscarding(t, 62) } 570 func TestDistantAnnouncementDiscarding63(t *testing.T) { testDistantAnnouncementDiscarding(t, 63) } 571 func TestDistantAnnouncementDiscarding64(t *testing.T) { testDistantAnnouncementDiscarding(t, 64) } 572 573 func testDistantAnnouncementDiscarding(t *testing.T, protocol int) { 574 //创建一个长链以导入和定义丢弃边界 575 hashes, blocks := makeChain(3*maxQueueDist, 0, genesis) 576 head := hashes[len(hashes)/2] 577 578 low, high := len(hashes)/2+maxUncleDist+1, len(hashes)/2-maxQueueDist-1 579 580 //创建一个测试仪并模拟上边链中间的头块 581 tester := newTester() 582 583 tester.lock.Lock() 584 tester.hashes = []common.Hash{head} 585 tester.blocks = map[common.Hash]*types.Block{head: blocks[head]} 586 tester.lock.Unlock() 587 588 headerFetcher := tester.makeHeaderFetcher("lower", blocks, -gatherSlack) 589 bodyFetcher := tester.makeBodyFetcher("lower", blocks, 0) 590 591 fetching := make(chan struct{}, 2) 592 tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- struct{}{} } 593 594 //确保丢弃数字低于阈值的块 595 tester.fetcher.Notify("lower", hashes[low], blocks[hashes[low]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 596 select { 597 case <-time.After(50 * time.Millisecond): 598 case <-fetching: 599 t.Fatalf("fetcher requested stale header") 600 } 601 //确保丢弃数字高于阈值的块 602 tester.fetcher.Notify("higher", hashes[high], blocks[hashes[high]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 603 select { 604 case <-time.After(50 * time.Millisecond): 605 case <-fetching: 606 t.Fatalf("fetcher requested future header") 607 } 608 } 609 610 //对等方用无效数字(即不匹配)宣布块的测试 611 //随后提供的头)作为恶意丢弃。 612 func TestInvalidNumberAnnouncement62(t *testing.T) { testInvalidNumberAnnouncement(t, 62) } 613 func TestInvalidNumberAnnouncement63(t *testing.T) { testInvalidNumberAnnouncement(t, 63) } 614 func TestInvalidNumberAnnouncement64(t *testing.T) { testInvalidNumberAnnouncement(t, 64) } 615 616 func testInvalidNumberAnnouncement(t *testing.T, protocol int) { 617 //创建一个块以导入和检查编号 618 hashes, blocks := makeChain(1, 0, genesis) 619 620 tester := newTester() 621 badHeaderFetcher := tester.makeHeaderFetcher("bad", blocks, -gatherSlack) 622 badBodyFetcher := tester.makeBodyFetcher("bad", blocks, 0) 623 624 imported := make(chan *types.Block) 625 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 626 627 //宣布一个有错误数字的块,检查是否立即丢弃 628 tester.fetcher.Notify("bad", hashes[0], 2, time.Now().Add(-arriveTimeout), badHeaderFetcher, badBodyFetcher) 629 verifyImportEvent(t, imported, false) 630 631 tester.lock.RLock() 632 dropped := tester.drops["bad"] 633 tester.lock.RUnlock() 634 635 if !dropped { 636 t.Fatalf("peer with invalid numbered announcement not dropped") 637 } 638 639 goodHeaderFetcher := tester.makeHeaderFetcher("good", blocks, -gatherSlack) 640 goodBodyFetcher := tester.makeBodyFetcher("good", blocks, 0) 641 //确保一个好的通知一滴一滴地通过 642 tester.fetcher.Notify("good", hashes[0], 1, time.Now().Add(-arriveTimeout), goodHeaderFetcher, goodBodyFetcher) 643 verifyImportEvent(t, imported, true) 644 645 tester.lock.RLock() 646 dropped = tester.drops["good"] 647 tester.lock.RUnlock() 648 649 if dropped { 650 t.Fatalf("peer with valid numbered announcement dropped") 651 } 652 verifyImportDone(t, imported) 653 } 654 655 //测试如果一个块为空(即仅限头),则不应该有body请求 656 //制作,而不是集管本身组装成一个整体。 657 func TestEmptyBlockShortCircuit62(t *testing.T) { testEmptyBlockShortCircuit(t, 62) } 658 func TestEmptyBlockShortCircuit63(t *testing.T) { testEmptyBlockShortCircuit(t, 63) } 659 func TestEmptyBlockShortCircuit64(t *testing.T) { testEmptyBlockShortCircuit(t, 64) } 660 661 func testEmptyBlockShortCircuit(t *testing.T, protocol int) { 662 //创建要导入的块链 663 hashes, blocks := makeChain(32, 0, genesis) 664 665 tester := newTester() 666 headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 667 bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 668 669 //为所有内部事件添加监视挂钩 670 fetching := make(chan []common.Hash) 671 tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- hashes } 672 673 completing := make(chan []common.Hash) 674 tester.fetcher.completingHook = func(hashes []common.Hash) { completing <- hashes } 675 676 imported := make(chan *types.Block) 677 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 678 679 //迭代地通知块,直到全部导入 680 for i := len(hashes) - 2; i >= 0; i-- { 681 tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) 682 683 //所有公告都应获取标题 684 verifyFetchingEvent(t, fetching, true) 685 686 //只有包含数据内容的块才应请求正文 687 verifyCompletingEvent(t, completing, len(blocks[hashes[i]].Transactions()) > 0 || len(blocks[hashes[i]].Uncles()) > 0) 688 689 //与构造无关,导入应该成功 690 verifyImportEvent(t, imported, true) 691 } 692 verifyImportDone(t, imported) 693 } 694 695 //测试对等端无法使用无限发送的无限内存 696 //阻止向节点发布公告,但即使面对此类攻击, 697 //取纸器仍在工作。 698 func TestHashMemoryExhaustionAttack62(t *testing.T) { testHashMemoryExhaustionAttack(t, 62) } 699 func TestHashMemoryExhaustionAttack63(t *testing.T) { testHashMemoryExhaustionAttack(t, 63) } 700 func TestHashMemoryExhaustionAttack64(t *testing.T) { testHashMemoryExhaustionAttack(t, 64) } 701 702 func testHashMemoryExhaustionAttack(t *testing.T, protocol int) { 703 //使用插入仪器的导入挂钩创建测试仪 704 tester := newTester() 705 706 imported, announces := make(chan *types.Block), int32(0) 707 tester.fetcher.importedHook = func(block *types.Block) { imported <- block } 708 tester.fetcher.announceChangeHook = func(hash common.Hash, added bool) { 709 if added { 710 atomic.AddInt32(&announces, 1) 711 } else { 712 atomic.AddInt32(&announces, -1) 713 } 714 } 715 //创建有效的链和无限的垃圾链 716 targetBlocks := hashLimit + 2*maxQueueDist 717 hashes, blocks := makeChain(targetBlocks, 0, genesis) 718 validHeaderFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) 719 validBodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) 720 721 attack, _ := makeChain(targetBlocks, 0, unknownBlock) 722 attackerHeaderFetcher := tester.makeHeaderFetcher("attacker", nil, -gatherSlack) 723 attackerBodyFetcher := tester.makeBodyFetcher("attacker", nil, 0) 724 725 //向测试人员提供来自攻击者的大量哈希集,以及来自有效对等端的有限哈希集 726 for i := 0; i < len(attack); i++ { 727 if i < maxQueueDist { 728 tester.fetcher.Notify("valid", hashes[len(hashes)-2-i], uint64(i+1), time.Now(), validHeaderFetcher, validBodyFetcher) 729 } 730 /*ter.fetcher.notify(“攻击者”,攻击[i],1/*不要距离下降*/,time.now(),攻击者headerfetcher,攻击者bodyfetcher) 731 } 732 如果计数:=atomic.loadint32(&announces);计数!=hashlimit+maxqueuedist_ 733 t.fatalf(“排队的公告计数不匹配:有%d,需要%d”,count,hashlimit+maxqueuedist) 734 } 735 //等待回迁完成 736 verifyimportcount(t,导入,maxqueuedist) 737 738 //馈送剩余的有效哈希以确保DOS保护状态保持干净 739 对于i:=len(hashes)-maxqueuedist-2;i>=0;i-- 740 tester.fetcher.notify(“valid”,hashes[i],uint64(len(hashes)-i-1),time.now().add(-arrieveTimeout),validHeaderFetcher,validBodyFetcher) 741 verifyimportevent(t,导入,真) 742 } 743 验证导入完成(T,导入) 744 } 745 746 //测试发送到获取程序的块(通过传播或通过哈希 747 //announces和retrievals)不要无限期地堆积起来,这样会耗尽可用的资源。 748 //系统内存。 749 func testblockmemoryxhausationattack(t*testing.t) 750 //使用插入指令的导入挂钩创建测试仪 751 测试仪:=新测试仪() 752 753 导入,排队:=make(chan*types.block),int32(0) 754 tester.fetcher.importedhook=func(block*types.block)imported<-block 755 tester.fetcher.queuechangehook=func(hash common.hash,added bool) 756 如果添加{ 757 Atomic.AddInt32(&Enqueued,1) 758 }否则{ 759 原子.addint32(&enqueued,-1) 760 } 761 } 762 //创建有效的链和一批悬空(但在范围内)块 763 目标块:=hashlimit+2*maxqueuedist 764 哈希,块:=makechain(targetBlocks,0,genesis) 765 攻击:=make(map[common.hash]*types.block) 766 对于i:=byte(0);len(attack)<blocklimit+2*maxqueuedist;i++ 767 哈希,块:=makechain(maxqueuedist-1,i,unknownblock) 768 对于u,哈希:=范围哈希[:maxQueueDist-2] 769 攻击[hash]=块[hash] 770 } 771 } 772 //尝试馈送所有攻击者块,确保只接受有限的批处理 773 对于uu,封锁:=距离攻击 774 tester.fetcher.enqueue(“攻击者”,block) 775 } 776 时间.睡眠(200*时间.毫秒) 777 如果排队:=atomic.loadint32(&enqueued);排队!=块限制{ 778 t.fatalf(“排队的块计数不匹配:有%d个,需要%d个”,排队,块限制) 779 } 780 //将一批有效的块排队,并检查是否允许新的对等机这样做 781 对于i:=0;i<maxqueuedist-1;i++ 782 tester.fetcher.enqueue(“有效”,blocks[hashes[len(hashes)-3-i]) 783 } 784 时间.睡眠(100*时间.毫秒) 785 如果排队:=atomic.loadint32(&enqueued);排队!=blocklimit+maxqueuedist-1_ 786 t.fatalf(“排队的块计数不匹配:有%d,需要%d”,排队,blocklimit+maxqueuedist-1) 787 } 788 /插入丢失的片段(和健全性检查导入) 789 tester.fetcher.enqueue(“有效”,blocks[hashes[len(hashes)-2]) 790 verifyimportcount(t,导入,maxqueuedist) 791 792 //将剩余的块分块插入以确保干净的DOS保护 793 对于i:=maxqueuedist;i<len(hashes)-1;i++ 794 tester.fetcher.enqueue(“有效”,blocks[hashes[len(hashes)-2-i]) 795 verifyimportevent(t,导入,真) 796 } 797 验证导入完成(T,导入) 798 }