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