github.com/quinndk/ethereum_read@v0.0.0-20181211143958-29c55eec3237/go-ethereum-master_read/les/retrieve.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package light implements on-demand retrieval capable state and chain objects 18 // for the Ethereum Light Client. 19 package les 20 21 import ( 22 "context" 23 "crypto/rand" 24 "encoding/binary" 25 "fmt" 26 "sync" 27 "time" 28 29 "github.com/ethereum/go-ethereum/common/mclock" 30 ) 31 32 var ( 33 retryQueue = time.Millisecond * 100 34 softRequestTimeout = time.Millisecond * 500 35 hardRequestTimeout = time.Second * 10 36 ) 37 38 // retrieveManager is a layer on top of requestDistributor which takes care of 39 // matching replies by request ID and handles timeouts and resends if necessary. 40 type retrieveManager struct { 41 dist *requestDistributor 42 peers *peerSet 43 serverPool peerSelector 44 45 lock sync.RWMutex 46 sentReqs map[uint64]*sentReq 47 } 48 49 // validatorFunc is a function that processes a reply message 50 type validatorFunc func(distPeer, *Msg) error 51 52 // peerSelector receives feedback info about response times and timeouts 53 type peerSelector interface { 54 adjustResponseTime(*poolEntry, time.Duration, bool) 55 } 56 57 // sentReq represents a request sent and tracked by retrieveManager 58 type sentReq struct { 59 rm *retrieveManager 60 req *distReq 61 id uint64 62 validate validatorFunc 63 64 eventsCh chan reqPeerEvent 65 stopCh chan struct{} 66 stopped bool 67 err error 68 69 lock sync.RWMutex // protect access to sentTo map 70 sentTo map[distPeer]sentReqToPeer 71 72 lastReqQueued bool // last request has been queued but not sent 73 lastReqSentTo distPeer // if not nil then last request has been sent to given peer but not timed out 74 reqSrtoCount int // number of requests that reached soft (but not hard) timeout 75 } 76 77 // sentReqToPeer notifies the request-from-peer goroutine (tryRequest) about a response 78 // delivered by the given peer. Only one delivery is allowed per request per peer, 79 // after which delivered is set to true, the validity of the response is sent on the 80 // valid channel and no more responses are accepted. 81 type sentReqToPeer struct { 82 delivered bool 83 valid chan bool 84 } 85 86 // reqPeerEvent is sent by the request-from-peer goroutine (tryRequest) to the 87 // request state machine (retrieveLoop) through the eventsCh channel. 88 type reqPeerEvent struct { 89 event int 90 peer distPeer 91 } 92 93 const ( 94 rpSent = iota // if peer == nil, not sent (no suitable peers) 95 rpSoftTimeout 96 rpHardTimeout 97 rpDeliveredValid 98 rpDeliveredInvalid 99 ) 100 101 // newRetrieveManager creates the retrieve manager 102 func newRetrieveManager(peers *peerSet, dist *requestDistributor, serverPool peerSelector) *retrieveManager { 103 return &retrieveManager{ 104 peers: peers, 105 dist: dist, 106 serverPool: serverPool, 107 sentReqs: make(map[uint64]*sentReq), 108 } 109 } 110 111 // retrieve sends a request (to multiple peers if necessary) and waits for an answer 112 // that is delivered through the deliver function and successfully validated by the 113 // validator callback. It returns when a valid answer is delivered or the context is 114 // cancelled. 115 func (rm *retrieveManager) retrieve(ctx context.Context, reqID uint64, req *distReq, val validatorFunc, shutdown chan struct{}) error { 116 sentReq := rm.sendReq(reqID, req, val) 117 select { 118 case <-sentReq.stopCh: 119 case <-ctx.Done(): 120 sentReq.stop(ctx.Err()) 121 case <-shutdown: 122 sentReq.stop(fmt.Errorf("Client is shutting down")) 123 } 124 return sentReq.getError() 125 } 126 127 // sendReq starts a process that keeps trying to retrieve a valid answer for a 128 // request from any suitable peers until stopped or succeeded. 129 func (rm *retrieveManager) sendReq(reqID uint64, req *distReq, val validatorFunc) *sentReq { 130 r := &sentReq{ 131 rm: rm, 132 req: req, 133 id: reqID, 134 sentTo: make(map[distPeer]sentReqToPeer), 135 stopCh: make(chan struct{}), 136 eventsCh: make(chan reqPeerEvent, 10), 137 validate: val, 138 } 139 140 canSend := req.canSend 141 req.canSend = func(p distPeer) bool { 142 // add an extra check to canSend: the request has not been sent to the same peer before 143 r.lock.RLock() 144 _, sent := r.sentTo[p] 145 r.lock.RUnlock() 146 return !sent && canSend(p) 147 } 148 149 request := req.request 150 req.request = func(p distPeer) func() { 151 // before actually sending the request, put an entry into the sentTo map 152 r.lock.Lock() 153 r.sentTo[p] = sentReqToPeer{false, make(chan bool, 1)} 154 r.lock.Unlock() 155 return request(p) 156 } 157 rm.lock.Lock() 158 rm.sentReqs[reqID] = r 159 rm.lock.Unlock() 160 161 go r.retrieveLoop() 162 return r 163 } 164 165 // deliver is called by the LES protocol manager to deliver reply messages to waiting requests 166 func (rm *retrieveManager) deliver(peer distPeer, msg *Msg) error { 167 rm.lock.RLock() 168 req, ok := rm.sentReqs[msg.ReqID] 169 rm.lock.RUnlock() 170 171 if ok { 172 return req.deliver(peer, msg) 173 } 174 return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID) 175 } 176 177 // reqStateFn represents a state of the retrieve loop state machine 178 type reqStateFn func() reqStateFn 179 180 // retrieveLoop is the retrieval state machine event loop 181 func (r *sentReq) retrieveLoop() { 182 go r.tryRequest() 183 r.lastReqQueued = true 184 state := r.stateRequesting 185 186 for state != nil { 187 state = state() 188 } 189 190 r.rm.lock.Lock() 191 delete(r.rm.sentReqs, r.id) 192 r.rm.lock.Unlock() 193 } 194 195 // stateRequesting: a request has been queued or sent recently; when it reaches soft timeout, 196 // a new request is sent to a new peer 197 func (r *sentReq) stateRequesting() reqStateFn { 198 select { 199 case ev := <-r.eventsCh: 200 r.update(ev) 201 switch ev.event { 202 case rpSent: 203 if ev.peer == nil { 204 // request send failed, no more suitable peers 205 if r.waiting() { 206 // we are already waiting for sent requests which may succeed so keep waiting 207 return r.stateNoMorePeers 208 } 209 // nothing to wait for, no more peers to ask, return with error 210 r.stop(ErrNoPeers) 211 // no need to go to stopped state because waiting() already returned false 212 return nil 213 } 214 case rpSoftTimeout: 215 // last request timed out, try asking a new peer 216 go r.tryRequest() 217 r.lastReqQueued = true 218 return r.stateRequesting 219 case rpDeliveredValid: 220 r.stop(nil) 221 return r.stateStopped 222 } 223 return r.stateRequesting 224 case <-r.stopCh: 225 return r.stateStopped 226 } 227 } 228 229 // stateNoMorePeers: could not send more requests because no suitable peers are available. 230 // Peers may become suitable for a certain request later or new peers may appear so we 231 // keep trying. 232 func (r *sentReq) stateNoMorePeers() reqStateFn { 233 select { 234 case <-time.After(retryQueue): 235 go r.tryRequest() 236 r.lastReqQueued = true 237 return r.stateRequesting 238 case ev := <-r.eventsCh: 239 r.update(ev) 240 if ev.event == rpDeliveredValid { 241 r.stop(nil) 242 return r.stateStopped 243 } 244 return r.stateNoMorePeers 245 case <-r.stopCh: 246 return r.stateStopped 247 } 248 } 249 250 // stateStopped: request succeeded or cancelled, just waiting for some peers 251 // to either answer or time out hard 252 func (r *sentReq) stateStopped() reqStateFn { 253 for r.waiting() { 254 r.update(<-r.eventsCh) 255 } 256 return nil 257 } 258 259 // update updates the queued/sent flags and timed out peers counter according to the event 260 func (r *sentReq) update(ev reqPeerEvent) { 261 switch ev.event { 262 case rpSent: 263 r.lastReqQueued = false 264 r.lastReqSentTo = ev.peer 265 case rpSoftTimeout: 266 r.lastReqSentTo = nil 267 r.reqSrtoCount++ 268 case rpHardTimeout: 269 r.reqSrtoCount-- 270 case rpDeliveredValid, rpDeliveredInvalid: 271 if ev.peer == r.lastReqSentTo { 272 r.lastReqSentTo = nil 273 } else { 274 r.reqSrtoCount-- 275 } 276 } 277 } 278 279 // waiting returns true if the retrieval mechanism is waiting for an answer from 280 // any peer 281 func (r *sentReq) waiting() bool { 282 return r.lastReqQueued || r.lastReqSentTo != nil || r.reqSrtoCount > 0 283 } 284 285 // tryRequest tries to send the request to a new peer and waits for it to either 286 // succeed or time out if it has been sent. It also sends the appropriate reqPeerEvent 287 // messages to the request's event channel. 288 func (r *sentReq) tryRequest() { 289 sent := r.rm.dist.queue(r.req) 290 var p distPeer 291 select { 292 case p = <-sent: 293 case <-r.stopCh: 294 if r.rm.dist.cancel(r.req) { 295 p = nil 296 } else { 297 p = <-sent 298 } 299 } 300 301 r.eventsCh <- reqPeerEvent{rpSent, p} 302 if p == nil { 303 return 304 } 305 306 reqSent := mclock.Now() 307 srto, hrto := false, false 308 309 r.lock.RLock() 310 s, ok := r.sentTo[p] 311 r.lock.RUnlock() 312 if !ok { 313 panic(nil) 314 } 315 316 defer func() { 317 // send feedback to server pool and remove peer if hard timeout happened 318 pp, ok := p.(*peer) 319 if ok && r.rm.serverPool != nil { 320 respTime := time.Duration(mclock.Now() - reqSent) 321 r.rm.serverPool.adjustResponseTime(pp.poolEntry, respTime, srto) 322 } 323 if hrto { 324 pp.Log().Debug("Request timed out hard") 325 if r.rm.peers != nil { 326 r.rm.peers.Unregister(pp.id) 327 } 328 } 329 330 r.lock.Lock() 331 delete(r.sentTo, p) 332 r.lock.Unlock() 333 }() 334 335 select { 336 case ok := <-s.valid: 337 if ok { 338 r.eventsCh <- reqPeerEvent{rpDeliveredValid, p} 339 } else { 340 r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p} 341 } 342 return 343 case <-time.After(softRequestTimeout): 344 srto = true 345 r.eventsCh <- reqPeerEvent{rpSoftTimeout, p} 346 } 347 348 select { 349 case ok := <-s.valid: 350 if ok { 351 r.eventsCh <- reqPeerEvent{rpDeliveredValid, p} 352 } else { 353 r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p} 354 } 355 case <-time.After(hardRequestTimeout): 356 hrto = true 357 r.eventsCh <- reqPeerEvent{rpHardTimeout, p} 358 } 359 } 360 361 // deliver a reply belonging to this request 362 func (r *sentReq) deliver(peer distPeer, msg *Msg) error { 363 r.lock.Lock() 364 defer r.lock.Unlock() 365 366 s, ok := r.sentTo[peer] 367 if !ok || s.delivered { 368 return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID) 369 } 370 valid := r.validate(peer, msg) == nil 371 r.sentTo[peer] = sentReqToPeer{true, s.valid} 372 s.valid <- valid 373 if !valid { 374 return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID) 375 } 376 return nil 377 } 378 379 // stop stops the retrieval process and sets an error code that will be returned 380 // by getError 381 func (r *sentReq) stop(err error) { 382 r.lock.Lock() 383 if !r.stopped { 384 r.stopped = true 385 r.err = err 386 close(r.stopCh) 387 } 388 r.lock.Unlock() 389 } 390 391 // getError returns any retrieval error (either internally generated or set by the 392 // stop function) after stopCh has been closed 393 func (r *sentReq) getError() error { 394 return r.err 395 } 396 397 // genReqID generates a new random request ID 398 func genReqID() uint64 { 399 var rnd [8]byte 400 rand.Read(rnd[:]) 401 return binary.BigEndian.Uint64(rnd[:]) 402 }