github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/neatptc/downloader/peer.go (about) 1 package downloader 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 "math/big" 8 "sort" 9 "sync" 10 "sync/atomic" 11 "time" 12 13 "github.com/neatio-net/neatio/chain/log" 14 "github.com/neatio-net/neatio/utilities/common" 15 "github.com/neatio-net/neatio/utilities/event" 16 ) 17 18 const ( 19 maxLackingHashes = 4096 20 measurementImpact = 0.1 21 ) 22 23 var ( 24 errAlreadyFetching = errors.New("already fetching blocks from peer") 25 errAlreadyRegistered = errors.New("peer is already registered") 26 errNotRegistered = errors.New("peer is not registered") 27 ) 28 29 type peerConnection struct { 30 id string 31 32 headerIdle int32 33 blockIdle int32 34 receiptIdle int32 35 stateIdle int32 36 37 headerThroughput float64 38 blockThroughput float64 39 receiptThroughput float64 40 stateThroughput float64 41 42 rtt time.Duration 43 44 headerStarted time.Time 45 blockStarted time.Time 46 receiptStarted time.Time 47 stateStarted time.Time 48 49 lacking map[common.Hash]struct{} 50 51 peer Peer 52 53 version int 54 log log.Logger 55 lock sync.RWMutex 56 } 57 58 type LightPeer interface { 59 Head() (common.Hash, *big.Int) 60 RequestHeadersByHash(common.Hash, int, int, bool) error 61 RequestHeadersByNumber(uint64, int, int, bool) error 62 } 63 64 type Peer interface { 65 LightPeer 66 RequestBodies([]common.Hash) error 67 RequestReceipts([]common.Hash) error 68 RequestNodeData([]common.Hash) error 69 } 70 71 type lightPeerWrapper struct { 72 peer LightPeer 73 } 74 75 func (w *lightPeerWrapper) Head() (common.Hash, *big.Int) { return w.peer.Head() } 76 func (w *lightPeerWrapper) RequestHeadersByHash(h common.Hash, amount int, skip int, reverse bool) error { 77 return w.peer.RequestHeadersByHash(h, amount, skip, reverse) 78 } 79 func (w *lightPeerWrapper) RequestHeadersByNumber(i uint64, amount int, skip int, reverse bool) error { 80 return w.peer.RequestHeadersByNumber(i, amount, skip, reverse) 81 } 82 func (w *lightPeerWrapper) RequestBodies([]common.Hash) error { 83 panic("RequestBodies not supported in light client mode sync") 84 } 85 func (w *lightPeerWrapper) RequestReceipts([]common.Hash) error { 86 panic("RequestReceipts not supported in light client mode sync") 87 } 88 func (w *lightPeerWrapper) RequestNodeData([]common.Hash) error { 89 panic("RequestNodeData not supported in light client mode sync") 90 } 91 92 func newPeerConnection(id string, version int, peer Peer, logger log.Logger) *peerConnection { 93 return &peerConnection{ 94 id: id, 95 lacking: make(map[common.Hash]struct{}), 96 97 peer: peer, 98 99 version: version, 100 log: logger, 101 } 102 } 103 104 func (p *peerConnection) Reset() { 105 p.lock.Lock() 106 defer p.lock.Unlock() 107 108 atomic.StoreInt32(&p.headerIdle, 0) 109 atomic.StoreInt32(&p.blockIdle, 0) 110 atomic.StoreInt32(&p.receiptIdle, 0) 111 atomic.StoreInt32(&p.stateIdle, 0) 112 113 p.headerThroughput = 0 114 p.blockThroughput = 0 115 p.receiptThroughput = 0 116 p.stateThroughput = 0 117 118 p.lacking = make(map[common.Hash]struct{}) 119 } 120 121 func (p *peerConnection) FetchHeaders(from uint64, count int) error { 122 123 if p.version < 62 { 124 panic(fmt.Sprintf("header fetch [eth/62+] requested on eth/%d", p.version)) 125 } 126 127 if !atomic.CompareAndSwapInt32(&p.headerIdle, 0, 1) { 128 return errAlreadyFetching 129 } 130 p.headerStarted = time.Now() 131 132 go p.peer.RequestHeadersByNumber(from, count, 0, false) 133 134 return nil 135 } 136 137 func (p *peerConnection) FetchBodies(request *fetchRequest) error { 138 139 if p.version < 62 { 140 panic(fmt.Sprintf("body fetch [eth/62+] requested on eth/%d", p.version)) 141 } 142 143 if !atomic.CompareAndSwapInt32(&p.blockIdle, 0, 1) { 144 return errAlreadyFetching 145 } 146 p.blockStarted = time.Now() 147 148 hashes := make([]common.Hash, 0, len(request.Headers)) 149 for _, header := range request.Headers { 150 hashes = append(hashes, header.Hash()) 151 } 152 go p.peer.RequestBodies(hashes) 153 154 return nil 155 } 156 157 func (p *peerConnection) FetchReceipts(request *fetchRequest) error { 158 159 if p.version < 63 { 160 panic(fmt.Sprintf("body fetch [eth/63+] requested on eth/%d", p.version)) 161 } 162 163 if !atomic.CompareAndSwapInt32(&p.receiptIdle, 0, 1) { 164 return errAlreadyFetching 165 } 166 p.receiptStarted = time.Now() 167 168 hashes := make([]common.Hash, 0, len(request.Headers)) 169 for _, header := range request.Headers { 170 hashes = append(hashes, header.Hash()) 171 } 172 go p.peer.RequestReceipts(hashes) 173 174 return nil 175 } 176 177 func (p *peerConnection) FetchNodeData(hashes []common.Hash) error { 178 179 if p.version < 63 { 180 panic(fmt.Sprintf("node data fetch [eth/63+] requested on eth/%d", p.version)) 181 } 182 183 if !atomic.CompareAndSwapInt32(&p.stateIdle, 0, 1) { 184 return errAlreadyFetching 185 } 186 p.stateStarted = time.Now() 187 188 go p.peer.RequestNodeData(hashes) 189 190 return nil 191 } 192 193 func (p *peerConnection) SetHeadersIdle(delivered int) { 194 p.setIdle(p.headerStarted, delivered, &p.headerThroughput, &p.headerIdle) 195 } 196 197 func (p *peerConnection) SetBlocksIdle(delivered int) { 198 p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle) 199 } 200 201 func (p *peerConnection) SetBodiesIdle(delivered int) { 202 p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle) 203 } 204 205 func (p *peerConnection) SetReceiptsIdle(delivered int) { 206 p.setIdle(p.receiptStarted, delivered, &p.receiptThroughput, &p.receiptIdle) 207 } 208 209 func (p *peerConnection) SetNodeDataIdle(delivered int) { 210 p.setIdle(p.stateStarted, delivered, &p.stateThroughput, &p.stateIdle) 211 } 212 213 func (p *peerConnection) setIdle(started time.Time, delivered int, throughput *float64, idle *int32) { 214 215 defer atomic.StoreInt32(idle, 0) 216 217 p.lock.Lock() 218 defer p.lock.Unlock() 219 220 if delivered == 0 { 221 *throughput = 0 222 return 223 } 224 225 elapsed := time.Since(started) + 1 226 measured := float64(delivered) / (float64(elapsed) / float64(time.Second)) 227 228 *throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured 229 p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed)) 230 231 p.log.Trace("Peer throughput measurements updated", 232 "hps", p.headerThroughput, "bps", p.blockThroughput, 233 "rps", p.receiptThroughput, "sps", p.stateThroughput, 234 "miss", len(p.lacking), "rtt", p.rtt) 235 } 236 237 func (p *peerConnection) HeaderCapacity(targetRTT time.Duration) int { 238 p.lock.RLock() 239 defer p.lock.RUnlock() 240 241 return int(math.Min(1+math.Max(1, p.headerThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxHeaderFetch))) 242 } 243 244 func (p *peerConnection) BlockCapacity(targetRTT time.Duration) int { 245 p.lock.RLock() 246 defer p.lock.RUnlock() 247 248 return int(math.Min(1+math.Max(1, p.blockThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxBlockFetch))) 249 } 250 251 func (p *peerConnection) ReceiptCapacity(targetRTT time.Duration) int { 252 p.lock.RLock() 253 defer p.lock.RUnlock() 254 255 return int(math.Min(1+math.Max(1, p.receiptThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxReceiptFetch))) 256 } 257 258 func (p *peerConnection) NodeDataCapacity(targetRTT time.Duration) int { 259 p.lock.RLock() 260 defer p.lock.RUnlock() 261 262 return int(math.Min(1+math.Max(1, p.stateThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxStateFetch))) 263 } 264 265 func (p *peerConnection) MarkLacking(hash common.Hash) { 266 p.lock.Lock() 267 defer p.lock.Unlock() 268 269 for len(p.lacking) >= maxLackingHashes { 270 for drop := range p.lacking { 271 delete(p.lacking, drop) 272 break 273 } 274 } 275 p.lacking[hash] = struct{}{} 276 } 277 278 func (p *peerConnection) Lacks(hash common.Hash) bool { 279 p.lock.RLock() 280 defer p.lock.RUnlock() 281 282 _, ok := p.lacking[hash] 283 return ok 284 } 285 286 type peerSet struct { 287 peers map[string]*peerConnection 288 newPeerFeed event.Feed 289 peerDropFeed event.Feed 290 lock sync.RWMutex 291 } 292 293 func newPeerSet() *peerSet { 294 return &peerSet{ 295 peers: make(map[string]*peerConnection), 296 } 297 } 298 299 func (ps *peerSet) SubscribeNewPeers(ch chan<- *peerConnection) event.Subscription { 300 return ps.newPeerFeed.Subscribe(ch) 301 } 302 303 func (ps *peerSet) SubscribePeerDrops(ch chan<- *peerConnection) event.Subscription { 304 return ps.peerDropFeed.Subscribe(ch) 305 } 306 307 func (ps *peerSet) Reset() { 308 ps.lock.RLock() 309 defer ps.lock.RUnlock() 310 311 for _, peer := range ps.peers { 312 peer.Reset() 313 } 314 } 315 316 func (ps *peerSet) Register(p *peerConnection) error { 317 318 p.rtt = ps.medianRTT() 319 320 ps.lock.Lock() 321 if _, ok := ps.peers[p.id]; ok { 322 ps.lock.Unlock() 323 return errAlreadyRegistered 324 } 325 if len(ps.peers) > 0 { 326 p.headerThroughput, p.blockThroughput, p.receiptThroughput, p.stateThroughput = 0, 0, 0, 0 327 328 for _, peer := range ps.peers { 329 peer.lock.RLock() 330 p.headerThroughput += peer.headerThroughput 331 p.blockThroughput += peer.blockThroughput 332 p.receiptThroughput += peer.receiptThroughput 333 p.stateThroughput += peer.stateThroughput 334 peer.lock.RUnlock() 335 } 336 p.headerThroughput /= float64(len(ps.peers)) 337 p.blockThroughput /= float64(len(ps.peers)) 338 p.receiptThroughput /= float64(len(ps.peers)) 339 p.stateThroughput /= float64(len(ps.peers)) 340 } 341 ps.peers[p.id] = p 342 ps.lock.Unlock() 343 344 ps.newPeerFeed.Send(p) 345 return nil 346 } 347 348 func (ps *peerSet) Unregister(id string) error { 349 ps.lock.Lock() 350 p, ok := ps.peers[id] 351 if !ok { 352 defer ps.lock.Unlock() 353 return errNotRegistered 354 } 355 delete(ps.peers, id) 356 ps.lock.Unlock() 357 358 ps.peerDropFeed.Send(p) 359 return nil 360 } 361 362 func (ps *peerSet) Peer(id string) *peerConnection { 363 ps.lock.RLock() 364 defer ps.lock.RUnlock() 365 366 return ps.peers[id] 367 } 368 369 func (ps *peerSet) Len() int { 370 ps.lock.RLock() 371 defer ps.lock.RUnlock() 372 373 return len(ps.peers) 374 } 375 376 func (ps *peerSet) AllPeers() []*peerConnection { 377 ps.lock.RLock() 378 defer ps.lock.RUnlock() 379 380 list := make([]*peerConnection, 0, len(ps.peers)) 381 for _, p := range ps.peers { 382 list = append(list, p) 383 } 384 return list 385 } 386 387 func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) { 388 idle := func(p *peerConnection) bool { 389 return atomic.LoadInt32(&p.headerIdle) == 0 390 } 391 throughput := func(p *peerConnection) float64 { 392 p.lock.RLock() 393 defer p.lock.RUnlock() 394 return p.headerThroughput 395 } 396 return ps.idlePeers(62, 64, idle, throughput) 397 } 398 399 func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) { 400 idle := func(p *peerConnection) bool { 401 return atomic.LoadInt32(&p.blockIdle) == 0 402 } 403 throughput := func(p *peerConnection) float64 { 404 p.lock.RLock() 405 defer p.lock.RUnlock() 406 return p.blockThroughput 407 } 408 return ps.idlePeers(62, 64, idle, throughput) 409 } 410 411 func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) { 412 idle := func(p *peerConnection) bool { 413 return atomic.LoadInt32(&p.receiptIdle) == 0 414 } 415 throughput := func(p *peerConnection) float64 { 416 p.lock.RLock() 417 defer p.lock.RUnlock() 418 return p.receiptThroughput 419 } 420 return ps.idlePeers(63, 64, idle, throughput) 421 } 422 423 func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) { 424 idle := func(p *peerConnection) bool { 425 return atomic.LoadInt32(&p.stateIdle) == 0 426 } 427 throughput := func(p *peerConnection) float64 { 428 p.lock.RLock() 429 defer p.lock.RUnlock() 430 return p.stateThroughput 431 } 432 return ps.idlePeers(63, 64, idle, throughput) 433 } 434 435 func (ps *peerSet) idlePeers(minProtocol, maxProtocol int, idleCheck func(*peerConnection) bool, throughput func(*peerConnection) float64) ([]*peerConnection, int) { 436 ps.lock.RLock() 437 defer ps.lock.RUnlock() 438 439 idle, total := make([]*peerConnection, 0, len(ps.peers)), 0 440 for _, p := range ps.peers { 441 if p.version >= minProtocol && p.version <= maxProtocol { 442 if idleCheck(p) { 443 idle = append(idle, p) 444 } 445 total++ 446 } 447 } 448 for i := 0; i < len(idle); i++ { 449 for j := i + 1; j < len(idle); j++ { 450 if throughput(idle[i]) < throughput(idle[j]) { 451 idle[i], idle[j] = idle[j], idle[i] 452 } 453 } 454 } 455 return idle, total 456 } 457 458 func (ps *peerSet) medianRTT() time.Duration { 459 460 ps.lock.RLock() 461 defer ps.lock.RUnlock() 462 463 rtts := make([]float64, 0, len(ps.peers)) 464 for _, p := range ps.peers { 465 p.lock.RLock() 466 rtts = append(rtts, float64(p.rtt)) 467 p.lock.RUnlock() 468 } 469 sort.Float64s(rtts) 470 471 median := rttMaxEstimate 472 if qosTuningPeers <= len(rtts) { 473 median = time.Duration(rtts[qosTuningPeers/2]) 474 } else if len(rtts) > 0 { 475 median = time.Duration(rtts[len(rtts)/2]) 476 } 477 478 if median < rttMinEstimate { 479 median = rttMinEstimate 480 } 481 if median > rttMaxEstimate { 482 median = rttMaxEstimate 483 } 484 return median 485 }