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