github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/downloader/peer.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 //包含下载程序的活动对等集,维护两个故障 26 //以及信誉指标,以确定块检索的优先级。 27 28 package downloader 29 30 import ( 31 "errors" 32 "fmt" 33 "math" 34 "math/big" 35 "sort" 36 "sync" 37 "sync/atomic" 38 "time" 39 40 "github.com/ethereum/go-ethereum/common" 41 "github.com/ethereum/go-ethereum/event" 42 "github.com/ethereum/go-ethereum/log" 43 ) 44 45 const ( 46 maxLackingHashes = 4096 //列表中允许或缺少项的最大项数 47 measurementImpact = 0.1 //单个度量对对等端最终吞吐量值的影响。 48 ) 49 50 var ( 51 errAlreadyFetching = errors.New("already fetching blocks from peer") 52 errAlreadyRegistered = errors.New("peer is already registered") 53 errNotRegistered = errors.New("peer is not registered") 54 ) 55 56 //对等连接表示从中检索哈希和块的活动对等。 57 type peerConnection struct { 58 id string //对等方的唯一标识符 59 60 headerIdle int32 //对等机的当前头活动状态(空闲=0,活动=1) 61 blockIdle int32 //对等机的当前块活动状态(空闲=0,活动=1) 62 receiptIdle int32 //对等机的当前接收活动状态(空闲=0,活动=1) 63 stateIdle int32 //对等机的当前节点数据活动状态(空闲=0,活动=1) 64 65 headerThroughput float64 //每秒可检索的头数 66 blockThroughput float64 //每秒可检索的块(体)数 67 receiptThroughput float64 //每秒可检索的接收数 68 stateThroughput float64 //每秒可检索的节点数据块数 69 70 rtt time.Duration //请求往返时间以跟踪响应(QoS) 71 72 headerStarted time.Time //上次头提取开始时的时间实例 73 blockStarted time.Time //上次块(体)提取开始时的时间实例 74 receiptStarted time.Time //上次接收提取开始时的时间实例 75 stateStarted time.Time //上次节点数据提取开始时的时间实例 76 77 lacking map[common.Hash]struct{} //不请求的哈希集(以前没有) 78 79 peer Peer 80 81 version int //ETH协议版本号转换策略 82 log log.Logger //上下文记录器,用于向对等日志添加额外信息 83 lock sync.RWMutex 84 } 85 86 //light peer封装了与远程light peer同步所需的方法。 87 type LightPeer interface { 88 Head() (common.Hash, *big.Int) 89 RequestHeadersByHash(common.Hash, int, int, bool) error 90 RequestHeadersByNumber(uint64, int, int, bool) error 91 } 92 93 //对等体封装了与远程完整对等体同步所需的方法。 94 type Peer interface { 95 LightPeer 96 RequestBodies([]common.Hash) error 97 RequestReceipts([]common.Hash) error 98 RequestNodeData([]common.Hash) error 99 } 100 101 //LightPeerWrapper包装了一个LightPeer结构,删除了仅限对等的方法。 102 type lightPeerWrapper struct { 103 peer LightPeer 104 } 105 106 func (w *lightPeerWrapper) Head() (common.Hash, *big.Int) { return w.peer.Head() } 107 func (w *lightPeerWrapper) RequestHeadersByHash(h common.Hash, amount int, skip int, reverse bool) error { 108 return w.peer.RequestHeadersByHash(h, amount, skip, reverse) 109 } 110 func (w *lightPeerWrapper) RequestHeadersByNumber(i uint64, amount int, skip int, reverse bool) error { 111 return w.peer.RequestHeadersByNumber(i, amount, skip, reverse) 112 } 113 func (w *lightPeerWrapper) RequestBodies([]common.Hash) error { 114 panic("RequestBodies not supported in light client mode sync") 115 } 116 func (w *lightPeerWrapper) RequestReceipts([]common.Hash) error { 117 panic("RequestReceipts not supported in light client mode sync") 118 } 119 func (w *lightPeerWrapper) RequestNodeData([]common.Hash) error { 120 panic("RequestNodeData not supported in light client mode sync") 121 } 122 123 //NexPeRead创建了一个新的下载器对等体。 124 func newPeerConnection(id string, version int, peer Peer, logger log.Logger) *peerConnection { 125 return &peerConnection{ 126 id: id, 127 lacking: make(map[common.Hash]struct{}), 128 129 peer: peer, 130 131 version: version, 132 log: logger, 133 } 134 } 135 136 //重置清除对等实体的内部状态。 137 func (p *peerConnection) Reset() { 138 p.lock.Lock() 139 defer p.lock.Unlock() 140 141 atomic.StoreInt32(&p.headerIdle, 0) 142 atomic.StoreInt32(&p.blockIdle, 0) 143 atomic.StoreInt32(&p.receiptIdle, 0) 144 atomic.StoreInt32(&p.stateIdle, 0) 145 146 p.headerThroughput = 0 147 p.blockThroughput = 0 148 p.receiptThroughput = 0 149 p.stateThroughput = 0 150 151 p.lacking = make(map[common.Hash]struct{}) 152 } 153 154 //fetchheaders向远程对等端发送头检索请求。 155 func (p *peerConnection) FetchHeaders(from uint64, count int) error { 156 //健全性检查协议版本 157 if p.version < 62 { 158 panic(fmt.Sprintf("header fetch [eth/62+] requested on eth/%d", p.version)) 159 } 160 //如果对等机已获取,则短路 161 if !atomic.CompareAndSwapInt32(&p.headerIdle, 0, 1) { 162 return errAlreadyFetching 163 } 164 p.headerStarted = time.Now() 165 166 //发出头检索请求(绝对向上,无间隙) 167 go p.peer.RequestHeadersByNumber(from, count, 0, false) 168 169 return nil 170 } 171 172 //fetchbodies向远程对等端发送一个块体检索请求。 173 func (p *peerConnection) FetchBodies(request *fetchRequest) error { 174 //健全性检查协议版本 175 if p.version < 62 { 176 panic(fmt.Sprintf("body fetch [eth/62+] requested on eth/%d", p.version)) 177 } 178 //如果对等机已获取,则短路 179 if !atomic.CompareAndSwapInt32(&p.blockIdle, 0, 1) { 180 return errAlreadyFetching 181 } 182 p.blockStarted = time.Now() 183 184 //将标题集转换为可检索切片 185 hashes := make([]common.Hash, 0, len(request.Headers)) 186 for _, header := range request.Headers { 187 hashes = append(hashes, header.Hash()) 188 } 189 go p.peer.RequestBodies(hashes) 190 191 return nil 192 } 193 194 //fetchreceipts向远程对等发送收据检索请求。 195 func (p *peerConnection) FetchReceipts(request *fetchRequest) error { 196 //健全性检查协议版本 197 if p.version < 63 { 198 panic(fmt.Sprintf("body fetch [eth/63+] requested on eth/%d", p.version)) 199 } 200 //如果对等机已获取,则短路 201 if !atomic.CompareAndSwapInt32(&p.receiptIdle, 0, 1) { 202 return errAlreadyFetching 203 } 204 p.receiptStarted = time.Now() 205 206 //将标题集转换为可检索切片 207 hashes := make([]common.Hash, 0, len(request.Headers)) 208 for _, header := range request.Headers { 209 hashes = append(hashes, header.Hash()) 210 } 211 go p.peer.RequestReceipts(hashes) 212 213 return nil 214 } 215 216 //FETCHNODEDATA向远程对等体发送节点状态数据检索请求。 217 func (p *peerConnection) FetchNodeData(hashes []common.Hash) error { 218 //健全性检查协议版本 219 if p.version < 63 { 220 panic(fmt.Sprintf("node data fetch [eth/63+] requested on eth/%d", p.version)) 221 } 222 //如果对等机已获取,则短路 223 if !atomic.CompareAndSwapInt32(&p.stateIdle, 0, 1) { 224 return errAlreadyFetching 225 } 226 p.stateStarted = time.Now() 227 228 go p.peer.RequestNodeData(hashes) 229 230 return nil 231 } 232 233 //setheadersidle将对等机设置为空闲,允许它执行新的头检索 234 //请求。它的估计头检索吞吐量用测量值更新。 235 //刚才。 236 func (p *peerConnection) SetHeadersIdle(delivered int) { 237 p.setIdle(p.headerStarted, delivered, &p.headerThroughput, &p.headerIdle) 238 } 239 240 //setblocksidle将对等机设置为空闲,允许它执行新的块检索 241 //请求。它的估计块检索吞吐量用测量的更新。 242 //刚才。 243 func (p *peerConnection) SetBlocksIdle(delivered int) { 244 p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle) 245 } 246 247 //setbodiesidle将对等机设置为空闲,允许它执行块体检索。 248 //请求。它的估计身体检索吞吐量是用测量值更新的。 249 //刚才。 250 func (p *peerConnection) SetBodiesIdle(delivered int) { 251 p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle) 252 } 253 254 //setReceiptSidle将对等机设置为空闲,允许它执行新的接收 255 //检索请求。更新其估计的收据检索吞吐量 256 //刚刚测量的。 257 func (p *peerConnection) SetReceiptsIdle(delivered int) { 258 p.setIdle(p.receiptStarted, delivered, &p.receiptThroughput, &p.receiptIdle) 259 } 260 261 //setnodedataidle将对等机设置为空闲,允许它执行新的状态trie 262 //数据检索请求。它的估计状态检索吞吐量被更新 263 //刚刚测量的。 264 func (p *peerConnection) SetNodeDataIdle(delivered int) { 265 p.setIdle(p.stateStarted, delivered, &p.stateThroughput, &p.stateIdle) 266 } 267 268 //setidle将对等机设置为idle,允许它执行新的检索请求。 269 //它的估计检索吞吐量用刚才测量的更新。 270 func (p *peerConnection) setIdle(started time.Time, delivered int, throughput *float64, idle *int32) { 271 //与扩展无关,确保对等端最终空闲 272 defer atomic.StoreInt32(idle, 0) 273 274 p.lock.Lock() 275 defer p.lock.Unlock() 276 277 //如果没有发送任何内容(硬超时/不可用数据),则将吞吐量降至最低 278 if delivered == 0 { 279 *throughput = 0 280 return 281 } 282 //否则,以新的测量来更新吞吐量。 283 elapsed := time.Since(started) + 1 //+1(ns)以确保非零除数 284 measured := float64(delivered) / (float64(elapsed) / float64(time.Second)) 285 286 *throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured 287 p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed)) 288 289 p.log.Trace("Peer throughput measurements updated", 290 "hps", p.headerThroughput, "bps", p.blockThroughput, 291 "rps", p.receiptThroughput, "sps", p.stateThroughput, 292 "miss", len(p.lacking), "rtt", p.rtt) 293 } 294 295 //HeaderCapacity根据其 296 //以前发现的吞吐量。 297 func (p *peerConnection) HeaderCapacity(targetRTT time.Duration) int { 298 p.lock.RLock() 299 defer p.lock.RUnlock() 300 301 return int(math.Min(1+math.Max(1, p.headerThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxHeaderFetch))) 302 } 303 304 //BlockCapacity根据其 305 //以前发现的吞吐量。 306 func (p *peerConnection) BlockCapacity(targetRTT time.Duration) int { 307 p.lock.RLock() 308 defer p.lock.RUnlock() 309 310 return int(math.Min(1+math.Max(1, p.blockThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxBlockFetch))) 311 } 312 313 //ReceiptCapacity根据其 314 //以前发现的吞吐量。 315 func (p *peerConnection) ReceiptCapacity(targetRTT time.Duration) int { 316 p.lock.RLock() 317 defer p.lock.RUnlock() 318 319 return int(math.Min(1+math.Max(1, p.receiptThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxReceiptFetch))) 320 } 321 322 //nodeDataCapacity根据其 323 //以前发现的吞吐量。 324 func (p *peerConnection) NodeDataCapacity(targetRTT time.Duration) int { 325 p.lock.RLock() 326 defer p.lock.RUnlock() 327 328 return int(math.Min(1+math.Max(1, p.stateThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxStateFetch))) 329 } 330 331 //MaxDebug将新实体添加到一组项目(块、收据、状态)中。 332 //已知某个对等机没有(即之前已被请求)。如果 333 //集合达到其最大允许容量,项目被随机丢弃。 334 func (p *peerConnection) MarkLacking(hash common.Hash) { 335 p.lock.Lock() 336 defer p.lock.Unlock() 337 338 for len(p.lacking) >= maxLackingHashes { 339 for drop := range p.lacking { 340 delete(p.lacking, drop) 341 break 342 } 343 } 344 p.lacking[hash] = struct{}{} 345 } 346 347 //缺少检索区块链项目的哈希是否在缺少的对等项上 348 //列出(即,我们是否知道同伴没有它)。 349 func (p *peerConnection) Lacks(hash common.Hash) bool { 350 p.lock.RLock() 351 defer p.lock.RUnlock() 352 353 _, ok := p.lacking[hash] 354 return ok 355 } 356 357 //对等集表示参与链的活动对等集 358 //下载过程。 359 type peerSet struct { 360 peers map[string]*peerConnection 361 newPeerFeed event.Feed 362 peerDropFeed event.Feed 363 lock sync.RWMutex 364 } 365 366 //new peer set创建一个新的peer set top跟踪活动的下载源。 367 func newPeerSet() *peerSet { 368 return &peerSet{ 369 peers: make(map[string]*peerConnection), 370 } 371 } 372 373 //订阅方订阅对等到达事件。 374 func (ps *peerSet) SubscribeNewPeers(ch chan<- *peerConnection) event.Subscription { 375 return ps.newPeerFeed.Subscribe(ch) 376 } 377 378 //订阅对等删除订阅对等离开事件。 379 func (ps *peerSet) SubscribePeerDrops(ch chan<- *peerConnection) event.Subscription { 380 return ps.peerDropFeed.Subscribe(ch) 381 } 382 383 //重置迭代当前对等集,并重置每个已知对等 384 //为下一批块检索做准备。 385 func (ps *peerSet) Reset() { 386 ps.lock.RLock() 387 defer ps.lock.RUnlock() 388 389 for _, peer := range ps.peers { 390 peer.Reset() 391 } 392 } 393 394 //寄存器向工作集中注入一个新的对等点,或者返回一个错误,如果 395 //对等机已经知道。 396 // 397 //该方法还将新对等机的起始吞吐量值设置为 398 //对所有现有同龄人的平均数,以使其有实际的使用机会 399 //用于数据检索。 400 func (ps *peerSet) Register(p *peerConnection) error { 401 //检索当前中间值RTT作为健全的默认值 402 p.rtt = ps.medianRTT() 403 404 //用一些有意义的默认值注册新的对等机 405 ps.lock.Lock() 406 if _, ok := ps.peers[p.id]; ok { 407 ps.lock.Unlock() 408 return errAlreadyRegistered 409 } 410 if len(ps.peers) > 0 { 411 p.headerThroughput, p.blockThroughput, p.receiptThroughput, p.stateThroughput = 0, 0, 0, 0 412 413 for _, peer := range ps.peers { 414 peer.lock.RLock() 415 p.headerThroughput += peer.headerThroughput 416 p.blockThroughput += peer.blockThroughput 417 p.receiptThroughput += peer.receiptThroughput 418 p.stateThroughput += peer.stateThroughput 419 peer.lock.RUnlock() 420 } 421 p.headerThroughput /= float64(len(ps.peers)) 422 p.blockThroughput /= float64(len(ps.peers)) 423 p.receiptThroughput /= float64(len(ps.peers)) 424 p.stateThroughput /= float64(len(ps.peers)) 425 } 426 ps.peers[p.id] = p 427 ps.lock.Unlock() 428 429 ps.newPeerFeed.Send(p) 430 return nil 431 } 432 433 //注销从活动集删除远程对等,进一步禁用 434 //对该特定实体采取的行动。 435 func (ps *peerSet) Unregister(id string) error { 436 ps.lock.Lock() 437 p, ok := ps.peers[id] 438 if !ok { 439 defer ps.lock.Unlock() 440 return errNotRegistered 441 } 442 delete(ps.peers, id) 443 ps.lock.Unlock() 444 445 ps.peerDropFeed.Send(p) 446 return nil 447 } 448 449 //对等端检索具有给定ID的注册对等端。 450 func (ps *peerSet) Peer(id string) *peerConnection { 451 ps.lock.RLock() 452 defer ps.lock.RUnlock() 453 454 return ps.peers[id] 455 } 456 457 //len返回集合中当前的对等数。 458 func (ps *peerSet) Len() int { 459 ps.lock.RLock() 460 defer ps.lock.RUnlock() 461 462 return len(ps.peers) 463 } 464 465 //Allpeers检索集合中所有对等方的简单列表。 466 func (ps *peerSet) AllPeers() []*peerConnection { 467 ps.lock.RLock() 468 defer ps.lock.RUnlock() 469 470 list := make([]*peerConnection, 0, len(ps.peers)) 471 for _, p := range ps.peers { 472 list = append(list, p) 473 } 474 return list 475 } 476 477 //HeaderIdlePeers检索当前所有头空闲对等的简单列表 478 //在活动对等集内,按其声誉排序。 479 func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) { 480 idle := func(p *peerConnection) bool { 481 return atomic.LoadInt32(&p.headerIdle) == 0 482 } 483 throughput := func(p *peerConnection) float64 { 484 p.lock.RLock() 485 defer p.lock.RUnlock() 486 return p.headerThroughput 487 } 488 return ps.idlePeers(62, 64, idle, throughput) 489 } 490 491 //BodyIdlePeers检索当前位于 492 //按其声誉排序的活动对等集。 493 func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) { 494 idle := func(p *peerConnection) bool { 495 return atomic.LoadInt32(&p.blockIdle) == 0 496 } 497 throughput := func(p *peerConnection) float64 { 498 p.lock.RLock() 499 defer p.lock.RUnlock() 500 return p.blockThroughput 501 } 502 return ps.idlePeers(62, 64, idle, throughput) 503 } 504 505 //ReceiptIdlePeers检索当前所有接收空闲对等的简单列表 506 //在活动对等集内,按其声誉排序。 507 func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) { 508 idle := func(p *peerConnection) bool { 509 return atomic.LoadInt32(&p.receiptIdle) == 0 510 } 511 throughput := func(p *peerConnection) float64 { 512 p.lock.RLock() 513 defer p.lock.RUnlock() 514 return p.receiptThroughput 515 } 516 return ps.idlePeers(63, 64, idle, throughput) 517 } 518 519 //nodedataidlepeers检索当前所有空闲节点数据的简单列表 520 //活动对等集内的对等点,按其声誉排序。 521 func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) { 522 idle := func(p *peerConnection) bool { 523 return atomic.LoadInt32(&p.stateIdle) == 0 524 } 525 throughput := func(p *peerConnection) float64 { 526 p.lock.RLock() 527 defer p.lock.RUnlock() 528 return p.stateThroughput 529 } 530 return ps.idlePeers(63, 64, idle, throughput) 531 } 532 533 //idle peers检索当前满足 534 //协议版本约束,使用提供的函数检查空闲。 535 //由此产生的一组对等机按其度量吞吐量进行排序。 536 func (ps *peerSet) idlePeers(minProtocol, maxProtocol int, idleCheck func(*peerConnection) bool, throughput func(*peerConnection) float64) ([]*peerConnection, int) { 537 ps.lock.RLock() 538 defer ps.lock.RUnlock() 539 540 idle, total := make([]*peerConnection, 0, len(ps.peers)), 0 541 for _, p := range ps.peers { 542 if p.version >= minProtocol && p.version <= maxProtocol { 543 if idleCheck(p) { 544 idle = append(idle, p) 545 } 546 total++ 547 } 548 } 549 for i := 0; i < len(idle); i++ { 550 for j := i + 1; j < len(idle); j++ { 551 if throughput(idle[i]) < throughput(idle[j]) { 552 idle[i], idle[j] = idle[j], idle[i] 553 } 554 } 555 } 556 return idle, total 557 } 558 559 //MediaNRTT返回对等集的中间RTT,只考虑调优 560 //如果有更多可用的对等机,则为对等机。 561 func (ps *peerSet) medianRTT() time.Duration { 562 //收集所有当前测量的往返时间 563 ps.lock.RLock() 564 defer ps.lock.RUnlock() 565 566 rtts := make([]float64, 0, len(ps.peers)) 567 for _, p := range ps.peers { 568 p.lock.RLock() 569 rtts = append(rtts, float64(p.rtt)) 570 p.lock.RUnlock() 571 } 572 sort.Float64s(rtts) 573 574 median := rttMaxEstimate 575 if qosTuningPeers <= len(rtts) { 576 median = time.Duration(rtts[qosTuningPeers/2]) //调优同行的中位数 577 } else if len(rtts) > 0 { 578 median = time.Duration(rtts[len(rtts)/2]) //我们连接的对等点的中位数(甚至保持一些基线QoS) 579 } 580 //将RTT限制为一些QoS默认值,与真正的RTT无关 581 if median < rttMinEstimate { 582 median = rttMinEstimate 583 } 584 if median > rttMaxEstimate { 585 median = rttMaxEstimate 586 } 587 return median 588 }