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