github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/retrieve.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:39</date> 10 //</624450096053882880> 11 12 13 //package light实现可按需检索的状态和链对象 14 //对于以太坊Light客户端。 15 package les 16 17 import ( 18 "context" 19 "crypto/rand" 20 "encoding/binary" 21 "fmt" 22 "sync" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common/mclock" 26 "github.com/ethereum/go-ethereum/light" 27 ) 28 29 var ( 30 retryQueue = time.Millisecond * 100 31 softRequestTimeout = time.Millisecond * 500 32 hardRequestTimeout = time.Second * 10 33 ) 34 35 //RetrieveManager是一个位于RequestDistributor之上的层,负责 36 //按请求ID匹配答复,并处理超时,必要时重新发送。 37 type retrieveManager struct { 38 dist *requestDistributor 39 peers *peerSet 40 serverPool peerSelector 41 42 lock sync.RWMutex 43 sentReqs map[uint64]*sentReq 44 } 45 46 //validatorfunc是一个处理回复消息的函数 47 type validatorFunc func(distPeer, *Msg) error 48 49 //peerSelector receives feedback info about response times and timeouts 50 type peerSelector interface { 51 adjustResponseTime(*poolEntry, time.Duration, bool) 52 } 53 54 //sentreq表示由retrievemanager发送和跟踪的请求 55 type sentReq struct { 56 rm *retrieveManager 57 req *distReq 58 id uint64 59 validate validatorFunc 60 61 eventsCh chan reqPeerEvent 62 stopCh chan struct{} 63 stopped bool 64 err error 65 66 lock sync.RWMutex //保护对Sento地图的访问 67 sentTo map[distPeer]sentReqToPeer 68 69 lastReqQueued bool //上一个请求已排队,但未发送 70 lastReqSentTo distPeer //如果不是零,则最后一个请求已发送给给定的对等方,但未超时。 71 reqSrtoCount int //达到软(但非硬)超时的请求数 72 } 73 74 //SentReqTopeer通知来自对等Goroutine(TryRequest)的请求有关响应 75 //由给定的对等方传递。每个对等端的每个请求只允许一次传递, 76 //在此之后,delivered设置为true,响应的有效性将发送到 77 //有效通道,不接受其他响应。 78 type sentReqToPeer struct { 79 delivered bool 80 valid chan bool 81 } 82 83 //ReqPeerEvent由Peer Goroutine(TryRequest)的请求发送到 84 //通过eventsch通道请求状态机(retrieveloop)。 85 type reqPeerEvent struct { 86 event int 87 peer distPeer 88 } 89 90 const ( 91 rpSent = iota //if peer == nil, not sent (no suitable peers) 92 rpSoftTimeout 93 rpHardTimeout 94 rpDeliveredValid 95 rpDeliveredInvalid 96 ) 97 98 //newRetrieveManager创建检索管理器 99 func newRetrieveManager(peers *peerSet, dist *requestDistributor, serverPool peerSelector) *retrieveManager { 100 return &retrieveManager{ 101 peers: peers, 102 dist: dist, 103 serverPool: serverPool, 104 sentReqs: make(map[uint64]*sentReq), 105 } 106 } 107 108 //检索发送请求(必要时发送给多个对等方)并等待响应 109 //通过传递函数传递并由 110 //验证程序回调。当传递有效答案或上下文为 111 //取消。 112 func (rm *retrieveManager) retrieve(ctx context.Context, reqID uint64, req *distReq, val validatorFunc, shutdown chan struct{}) error { 113 sentReq := rm.sendReq(reqID, req, val) 114 select { 115 case <-sentReq.stopCh: 116 case <-ctx.Done(): 117 sentReq.stop(ctx.Err()) 118 case <-shutdown: 119 sentReq.stop(fmt.Errorf("Client is shutting down")) 120 } 121 return sentReq.getError() 122 } 123 124 //sendreq启动一个进程,该进程不断尝试为 125 //在停止或成功之前,从任何合适的对等方请求。 126 func (rm *retrieveManager) sendReq(reqID uint64, req *distReq, val validatorFunc) *sentReq { 127 r := &sentReq{ 128 rm: rm, 129 req: req, 130 id: reqID, 131 sentTo: make(map[distPeer]sentReqToPeer), 132 stopCh: make(chan struct{}), 133 eventsCh: make(chan reqPeerEvent, 10), 134 validate: val, 135 } 136 137 canSend := req.canSend 138 req.canSend = func(p distPeer) bool { 139 //为cansend添加额外的检查:请求以前没有发送到同一个对等机 140 r.lock.RLock() 141 _, sent := r.sentTo[p] 142 r.lock.RUnlock() 143 return !sent && canSend(p) 144 } 145 146 request := req.request 147 req.request = func(p distPeer) func() { 148 //在实际发送请求之前,在sentto映射中输入一个条目 149 r.lock.Lock() 150 r.sentTo[p] = sentReqToPeer{false, make(chan bool, 1)} 151 r.lock.Unlock() 152 return request(p) 153 } 154 rm.lock.Lock() 155 rm.sentReqs[reqID] = r 156 rm.lock.Unlock() 157 158 go r.retrieveLoop() 159 return r 160 } 161 162 //LES协议管理器调用Deliver将回复消息传递给等待的请求。 163 func (rm *retrieveManager) deliver(peer distPeer, msg *Msg) error { 164 rm.lock.RLock() 165 req, ok := rm.sentReqs[msg.ReqID] 166 rm.lock.RUnlock() 167 168 if ok { 169 return req.deliver(peer, msg) 170 } 171 return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID) 172 } 173 174 //reqstatefn表示检索循环状态机的状态 175 type reqStateFn func() reqStateFn 176 177 //RetrieveLoop是检索状态机事件循环 178 func (r *sentReq) retrieveLoop() { 179 go r.tryRequest() 180 r.lastReqQueued = true 181 state := r.stateRequesting 182 183 for state != nil { 184 state = state() 185 } 186 187 r.rm.lock.Lock() 188 delete(r.rm.sentReqs, r.id) 189 r.rm.lock.Unlock() 190 } 191 192 //状态请求:请求最近已排队或发送;当达到软超时时, 193 //将向新对等发送新请求 194 func (r *sentReq) stateRequesting() reqStateFn { 195 select { 196 case ev := <-r.eventsCh: 197 r.update(ev) 198 switch ev.event { 199 case rpSent: 200 if ev.peer == nil { 201 //请求发送失败,没有合适的对等机 202 if r.waiting() { 203 //我们已经在等待可能成功的已发送请求,请继续等待 204 return r.stateNoMorePeers 205 } 206 //无需等待,无需询问其他对等方,返回时出错 207 r.stop(light.ErrNoPeers) 208 //无需转到停止状态,因为waiting()已返回false 209 return nil 210 } 211 case rpSoftTimeout: 212 //上次请求超时,请尝试询问新的对等方 213 go r.tryRequest() 214 r.lastReqQueued = true 215 return r.stateRequesting 216 case rpDeliveredInvalid: 217 //如果是上次发送的请求(更新时设置为nil),则启动新的请求。 218 if !r.lastReqQueued && r.lastReqSentTo == nil { 219 go r.tryRequest() 220 r.lastReqQueued = true 221 } 222 return r.stateRequesting 223 case rpDeliveredValid: 224 r.stop(nil) 225 return r.stateStopped 226 } 227 return r.stateRequesting 228 case <-r.stopCh: 229 return r.stateStopped 230 } 231 } 232 233 //StateNoMorepeers:无法发送更多请求,因为没有合适的对等机可用。 234 //对等方稍后可能会适合某个请求,或者可能会出现新的对等方,因此我们 235 //继续努力。 236 func (r *sentReq) stateNoMorePeers() reqStateFn { 237 select { 238 case <-time.After(retryQueue): 239 go r.tryRequest() 240 r.lastReqQueued = true 241 return r.stateRequesting 242 case ev := <-r.eventsCh: 243 r.update(ev) 244 if ev.event == rpDeliveredValid { 245 r.stop(nil) 246 return r.stateStopped 247 } 248 if r.waiting() { 249 return r.stateNoMorePeers 250 } 251 r.stop(light.ErrNoPeers) 252 return nil 253 case <-r.stopCh: 254 return r.stateStopped 255 } 256 } 257 258 //Statestopped:请求成功或取消,只是等待一些对等方 259 //要么回答,要么很难超时 260 func (r *sentReq) stateStopped() reqStateFn { 261 for r.waiting() { 262 r.update(<-r.eventsCh) 263 } 264 return nil 265 } 266 267 //更新根据事件更新排队/发送标志和超时对等计数器 268 func (r *sentReq) update(ev reqPeerEvent) { 269 switch ev.event { 270 case rpSent: 271 r.lastReqQueued = false 272 r.lastReqSentTo = ev.peer 273 case rpSoftTimeout: 274 r.lastReqSentTo = nil 275 r.reqSrtoCount++ 276 case rpHardTimeout: 277 r.reqSrtoCount-- 278 case rpDeliveredValid, rpDeliveredInvalid: 279 if ev.peer == r.lastReqSentTo { 280 r.lastReqSentTo = nil 281 } else { 282 r.reqSrtoCount-- 283 } 284 } 285 } 286 287 //如果检索机制正在等待来自的答案,则waiting返回true。 288 //任何同龄人 289 func (r *sentReq) waiting() bool { 290 return r.lastReqQueued || r.lastReqSentTo != nil || r.reqSrtoCount > 0 291 } 292 293 //TryRequest尝试将请求发送到新的对等机,并等待它 294 //succeed or time out if it has been sent. It also sends the appropriate reqPeerEvent 295 //发送到请求的事件通道的消息。 296 func (r *sentReq) tryRequest() { 297 sent := r.rm.dist.queue(r.req) 298 var p distPeer 299 select { 300 case p = <-sent: 301 case <-r.stopCh: 302 if r.rm.dist.cancel(r.req) { 303 p = nil 304 } else { 305 p = <-sent 306 } 307 } 308 309 r.eventsCh <- reqPeerEvent{rpSent, p} 310 if p == nil { 311 return 312 } 313 314 reqSent := mclock.Now() 315 srto, hrto := false, false 316 317 r.lock.RLock() 318 s, ok := r.sentTo[p] 319 r.lock.RUnlock() 320 if !ok { 321 panic(nil) 322 } 323 324 defer func() { 325 //向服务器池发送反馈,并在发生硬超时时删除对等机 326 pp, ok := p.(*peer) 327 if ok && r.rm.serverPool != nil { 328 respTime := time.Duration(mclock.Now() - reqSent) 329 r.rm.serverPool.adjustResponseTime(pp.poolEntry, respTime, srto) 330 } 331 if hrto { 332 pp.Log().Debug("Request timed out hard") 333 if r.rm.peers != nil { 334 r.rm.peers.Unregister(pp.id) 335 } 336 } 337 338 r.lock.Lock() 339 delete(r.sentTo, p) 340 r.lock.Unlock() 341 }() 342 343 select { 344 case ok := <-s.valid: 345 if ok { 346 r.eventsCh <- reqPeerEvent{rpDeliveredValid, p} 347 } else { 348 r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p} 349 } 350 return 351 case <-time.After(softRequestTimeout): 352 srto = true 353 r.eventsCh <- reqPeerEvent{rpSoftTimeout, p} 354 } 355 356 select { 357 case ok := <-s.valid: 358 if ok { 359 r.eventsCh <- reqPeerEvent{rpDeliveredValid, p} 360 } else { 361 r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p} 362 } 363 case <-time.After(hardRequestTimeout): 364 hrto = true 365 r.eventsCh <- reqPeerEvent{rpHardTimeout, p} 366 } 367 } 368 369 //传递属于此请求的答复 370 func (r *sentReq) deliver(peer distPeer, msg *Msg) error { 371 r.lock.Lock() 372 defer r.lock.Unlock() 373 374 s, ok := r.sentTo[peer] 375 if !ok || s.delivered { 376 return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID) 377 } 378 valid := r.validate(peer, msg) == nil 379 r.sentTo[peer] = sentReqToPeer{true, s.valid} 380 s.valid <- valid 381 if !valid { 382 return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID) 383 } 384 return nil 385 } 386 387 //停止停止检索进程并设置将返回的错误代码 388 //通过获得错误 389 func (r *sentReq) stop(err error) { 390 r.lock.Lock() 391 if !r.stopped { 392 r.stopped = true 393 r.err = err 394 close(r.stopCh) 395 } 396 r.lock.Unlock() 397 } 398 399 //GetError返回任何检索错误(由 400 //停止功能)停止后 401 func (r *sentReq) getError() error { 402 return r.err 403 } 404 405 //genreqid生成新的随机请求ID 406 func genReqID() uint64 { 407 var rnd [8]byte 408 rand.Read(rnd[:]) 409 return binary.BigEndian.Uint64(rnd[:]) 410 } 411