github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:38</date> 10 //</624342634143420416> 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 //上次头提取开始时的时间实例 61 blockStarted time.Time //上次块(体)提取开始时的时间实例 62 receiptStarted time.Time //上次接收提取开始时的时间实例 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向远程对等发送收据检索请求。 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 //setblocksidle将对等机设置为空闲,允许它执行新的块检索 229 //请求。它的估计块检索吞吐量用测量的更新。 230 //刚才。 231 func (p *peerConnection) SetBlocksIdle(delivered int) { 232 p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle) 233 } 234 235 //setbodiesidle将对等机设置为空闲,允许它执行块体检索。 236 //请求。它的估计身体检索吞吐量是用测量值更新的。 237 //刚才。 238 func (p *peerConnection) SetBodiesIdle(delivered int) { 239 p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle) 240 } 241 242 //setReceiptSidle将对等机设置为空闲,允许它执行新的接收 243 //检索请求。更新其估计的收据检索吞吐量 244 //刚刚测量的。 245 func (p *peerConnection) SetReceiptsIdle(delivered int) { 246 p.setIdle(p.receiptStarted, delivered, &p.receiptThroughput, &p.receiptIdle) 247 } 248 249 //setnodedataidle将对等机设置为空闲,允许它执行新的状态trie 250 //数据检索请求。它的估计状态检索吞吐量被更新 251 //刚刚测量的。 252 func (p *peerConnection) SetNodeDataIdle(delivered int) { 253 p.setIdle(p.stateStarted, delivered, &p.stateThroughput, &p.stateIdle) 254 } 255 256 //setidle将对等机设置为idle,允许它执行新的检索请求。 257 //它的估计检索吞吐量用刚才测量的更新。 258 func (p *peerConnection) setIdle(started time.Time, delivered int, throughput *float64, idle *int32) { 259 //与扩展无关,确保对等端最终空闲 260 defer atomic.StoreInt32(idle, 0) 261 262 p.lock.Lock() 263 defer p.lock.Unlock() 264 265 //如果没有发送任何内容(硬超时/不可用数据),则将吞吐量降至最低 266 if delivered == 0 { 267 *throughput = 0 268 return 269 } 270 //否则,以新的测量来更新吞吐量。 271 elapsed := time.Since(started) + 1 //+1(ns)以确保非零除数 272 measured := float64(delivered) / (float64(elapsed) / float64(time.Second)) 273 274 *throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured 275 p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed)) 276 277 p.log.Trace("Peer throughput measurements updated", 278 "hps", p.headerThroughput, "bps", p.blockThroughput, 279 "rps", p.receiptThroughput, "sps", p.stateThroughput, 280 "miss", len(p.lacking), "rtt", p.rtt) 281 } 282 283 //HeaderCapacity根据其 284 //以前发现的吞吐量。 285 func (p *peerConnection) HeaderCapacity(targetRTT time.Duration) int { 286 p.lock.RLock() 287 defer p.lock.RUnlock() 288 289 return int(math.Min(1+math.Max(1, p.headerThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxHeaderFetch))) 290 } 291 292 //BlockCapacity根据其 293 //以前发现的吞吐量。 294 func (p *peerConnection) BlockCapacity(targetRTT time.Duration) int { 295 p.lock.RLock() 296 defer p.lock.RUnlock() 297 298 return int(math.Min(1+math.Max(1, p.blockThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxBlockFetch))) 299 } 300 301 //ReceiptCapacity根据其 302 //以前发现的吞吐量。 303 func (p *peerConnection) ReceiptCapacity(targetRTT time.Duration) int { 304 p.lock.RLock() 305 defer p.lock.RUnlock() 306 307 return int(math.Min(1+math.Max(1, p.receiptThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxReceiptFetch))) 308 } 309 310 //nodeDataCapacity根据其 311 //以前发现的吞吐量。 312 func (p *peerConnection) NodeDataCapacity(targetRTT time.Duration) int { 313 p.lock.RLock() 314 defer p.lock.RUnlock() 315 316 return int(math.Min(1+math.Max(1, p.stateThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxStateFetch))) 317 } 318 319 //MaxDebug将新实体添加到一组项目(块、收据、状态)中。 320 //已知某个对等机没有(即之前已被请求)。如果 321 //集合达到其最大允许容量,项目被随机丢弃。 322 func (p *peerConnection) MarkLacking(hash common.Hash) { 323 p.lock.Lock() 324 defer p.lock.Unlock() 325 326 for len(p.lacking) >= maxLackingHashes { 327 for drop := range p.lacking { 328 delete(p.lacking, drop) 329 break 330 } 331 } 332 p.lacking[hash] = struct{}{} 333 } 334 335 //缺少检索区块链项目的哈希是否在缺少的对等项上 336 //列出(即,我们是否知道同伴没有它)。 337 func (p *peerConnection) Lacks(hash common.Hash) bool { 338 p.lock.RLock() 339 defer p.lock.RUnlock() 340 341 _, ok := p.lacking[hash] 342 return ok 343 } 344 345 //对等集表示参与链的活动对等集 346 //下载过程。 347 type peerSet struct { 348 peers map[string]*peerConnection 349 newPeerFeed event.Feed 350 peerDropFeed event.Feed 351 lock sync.RWMutex 352 } 353 354 //new peer set创建一个新的peer set top跟踪活动的下载源。 355 func newPeerSet() *peerSet { 356 return &peerSet{ 357 peers: make(map[string]*peerConnection), 358 } 359 } 360 361 //订阅方订阅对等到达事件。 362 func (ps *peerSet) SubscribeNewPeers(ch chan<- *peerConnection) event.Subscription { 363 return ps.newPeerFeed.Subscribe(ch) 364 } 365 366 //订阅对等删除订阅对等离开事件。 367 func (ps *peerSet) SubscribePeerDrops(ch chan<- *peerConnection) event.Subscription { 368 return ps.peerDropFeed.Subscribe(ch) 369 } 370 371 //重置迭代当前对等集,并重置每个已知对等 372 //为下一批块检索做准备。 373 func (ps *peerSet) Reset() { 374 ps.lock.RLock() 375 defer ps.lock.RUnlock() 376 377 for _, peer := range ps.peers { 378 peer.Reset() 379 } 380 } 381 382 //寄存器向工作集中注入一个新的对等点,或者返回一个错误,如果 383 //对等机已经知道。 384 // 385 //该方法还将新对等机的起始吞吐量值设置为 386 //对所有现有同龄人的平均数,以使其有实际的使用机会 387 //用于数据检索。 388 func (ps *peerSet) Register(p *peerConnection) error { 389 //检索当前中间值RTT作为健全的默认值 390 p.rtt = ps.medianRTT() 391 392 //用一些有意义的默认值注册新的对等机 393 ps.lock.Lock() 394 if _, ok := ps.peers[p.id]; ok { 395 ps.lock.Unlock() 396 return errAlreadyRegistered 397 } 398 if len(ps.peers) > 0 { 399 p.headerThroughput, p.blockThroughput, p.receiptThroughput, p.stateThroughput = 0, 0, 0, 0 400 401 for _, peer := range ps.peers { 402 peer.lock.RLock() 403 p.headerThroughput += peer.headerThroughput 404 p.blockThroughput += peer.blockThroughput 405 p.receiptThroughput += peer.receiptThroughput 406 p.stateThroughput += peer.stateThroughput 407 peer.lock.RUnlock() 408 } 409 p.headerThroughput /= float64(len(ps.peers)) 410 p.blockThroughput /= float64(len(ps.peers)) 411 p.receiptThroughput /= float64(len(ps.peers)) 412 p.stateThroughput /= float64(len(ps.peers)) 413 } 414 ps.peers[p.id] = p 415 ps.lock.Unlock() 416 417 ps.newPeerFeed.Send(p) 418 return nil 419 } 420 421 //注销从活动集删除远程对等,进一步禁用 422 //对该特定实体采取的行动。 423 func (ps *peerSet) Unregister(id string) error { 424 ps.lock.Lock() 425 p, ok := ps.peers[id] 426 if !ok { 427 defer ps.lock.Unlock() 428 return errNotRegistered 429 } 430 delete(ps.peers, id) 431 ps.lock.Unlock() 432 433 ps.peerDropFeed.Send(p) 434 return nil 435 } 436 437 //对等端检索具有给定ID的注册对等端。 438 func (ps *peerSet) Peer(id string) *peerConnection { 439 ps.lock.RLock() 440 defer ps.lock.RUnlock() 441 442 return ps.peers[id] 443 } 444 445 //len返回集合中当前的对等数。 446 func (ps *peerSet) Len() int { 447 ps.lock.RLock() 448 defer ps.lock.RUnlock() 449 450 return len(ps.peers) 451 } 452 453 //Allpeers检索集合中所有对等方的简单列表。 454 func (ps *peerSet) AllPeers() []*peerConnection { 455 ps.lock.RLock() 456 defer ps.lock.RUnlock() 457 458 list := make([]*peerConnection, 0, len(ps.peers)) 459 for _, p := range ps.peers { 460 list = append(list, p) 461 } 462 return list 463 } 464 465 //HeaderIdlePeers检索当前所有头空闲对等的简单列表 466 //在活动对等集内,按其声誉排序。 467 func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) { 468 idle := func(p *peerConnection) bool { 469 return atomic.LoadInt32(&p.headerIdle) == 0 470 } 471 throughput := func(p *peerConnection) float64 { 472 p.lock.RLock() 473 defer p.lock.RUnlock() 474 return p.headerThroughput 475 } 476 return ps.idlePeers(62, 64, idle, throughput) 477 } 478 479 //BodyIdlePeers检索当前位于 480 //按其声誉排序的活动对等集。 481 func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) { 482 idle := func(p *peerConnection) bool { 483 return atomic.LoadInt32(&p.blockIdle) == 0 484 } 485 throughput := func(p *peerConnection) float64 { 486 p.lock.RLock() 487 defer p.lock.RUnlock() 488 return p.blockThroughput 489 } 490 return ps.idlePeers(62, 64, idle, throughput) 491 } 492 493 //ReceiptIdlePeers检索当前所有接收空闲对等的简单列表 494 //在活动对等集内,按其声誉排序。 495 func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) { 496 idle := func(p *peerConnection) bool { 497 return atomic.LoadInt32(&p.receiptIdle) == 0 498 } 499 throughput := func(p *peerConnection) float64 { 500 p.lock.RLock() 501 defer p.lock.RUnlock() 502 return p.receiptThroughput 503 } 504 return ps.idlePeers(63, 64, idle, throughput) 505 } 506 507 //nodedataidlepeers检索当前所有空闲节点数据的简单列表 508 //活动对等集内的对等点,按其声誉排序。 509 func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) { 510 idle := func(p *peerConnection) bool { 511 return atomic.LoadInt32(&p.stateIdle) == 0 512 } 513 throughput := func(p *peerConnection) float64 { 514 p.lock.RLock() 515 defer p.lock.RUnlock() 516 return p.stateThroughput 517 } 518 return ps.idlePeers(63, 64, idle, throughput) 519 } 520 521 //idle peers检索当前满足 522 //协议版本约束,使用提供的函数检查空闲。 523 //由此产生的一组对等机按其度量吞吐量进行排序。 524 func (ps *peerSet) idlePeers(minProtocol, maxProtocol int, idleCheck func(*peerConnection) bool, throughput func(*peerConnection) float64) ([]*peerConnection, int) { 525 ps.lock.RLock() 526 defer ps.lock.RUnlock() 527 528 idle, total := make([]*peerConnection, 0, len(ps.peers)), 0 529 for _, p := range ps.peers { 530 if p.version >= minProtocol && p.version <= maxProtocol { 531 if idleCheck(p) { 532 idle = append(idle, p) 533 } 534 total++ 535 } 536 } 537 for i := 0; i < len(idle); i++ { 538 for j := i + 1; j < len(idle); j++ { 539 if throughput(idle[i]) < throughput(idle[j]) { 540 idle[i], idle[j] = idle[j], idle[i] 541 } 542 } 543 } 544 return idle, total 545 } 546 547 //MediaNRTT返回对等集的中间RTT,只考虑调优 548 //如果有更多可用的对等机,则为对等机。 549 func (ps *peerSet) medianRTT() time.Duration { 550 //收集所有当前测量的往返时间 551 ps.lock.RLock() 552 defer ps.lock.RUnlock() 553 554 rtts := make([]float64, 0, len(ps.peers)) 555 for _, p := range ps.peers { 556 p.lock.RLock() 557 rtts = append(rtts, float64(p.rtt)) 558 p.lock.RUnlock() 559 } 560 sort.Float64s(rtts) 561 562 median := rttMaxEstimate 563 if qosTuningPeers <= len(rtts) { 564 median = time.Duration(rtts[qosTuningPeers/2]) //调优同行的中位数 565 } else if len(rtts) > 0 { 566 median = time.Duration(rtts[len(rtts)/2]) //我们连接的对等点的中位数(甚至保持一些基线QoS) 567 } 568 //将RTT限制为一些QoS默认值,与真正的RTT无关 569 if median < rttMinEstimate { 570 median = rttMinEstimate 571 } 572 if median > rttMaxEstimate { 573 median = rttMaxEstimate 574 } 575 return median 576 } 577