github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/p2p/pex/pex_reactor.go (about) 1 package pex 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "sync" 8 "time" 9 10 "github.com/tendermint/go-amino" 11 12 "github.com/franono/tendermint/libs/cmap" 13 tmmath "github.com/franono/tendermint/libs/math" 14 tmrand "github.com/franono/tendermint/libs/rand" 15 "github.com/franono/tendermint/libs/service" 16 "github.com/franono/tendermint/p2p" 17 "github.com/franono/tendermint/p2p/conn" 18 ) 19 20 type Peer = p2p.Peer 21 22 const ( 23 // PexChannel is a channel for PEX messages 24 PexChannel = byte(0x00) 25 26 // over-estimate of max NetAddress size 27 // hexID (40) + IP (16) + Port (2) + Name (100) ... 28 // NOTE: dont use massive DNS name .. 29 maxAddressSize = 256 30 31 // NOTE: amplificaiton factor! 32 // small request results in up to maxMsgSize response 33 maxMsgSize = maxAddressSize * maxGetSelection 34 35 // ensure we have enough peers 36 defaultEnsurePeersPeriod = 30 * time.Second 37 38 // Seed/Crawler constants 39 40 // minTimeBetweenCrawls is a minimum time between attempts to crawl a peer. 41 minTimeBetweenCrawls = 2 * time.Minute 42 43 // check some peers every this 44 crawlPeerPeriod = 30 * time.Second 45 46 maxAttemptsToDial = 16 // ~ 35h in total (last attempt - 18h) 47 48 // if node connects to seed, it does not have any trusted peers. 49 // Especially in the beginning, node should have more trusted peers than 50 // untrusted. 51 biasToSelectNewPeers = 30 // 70 to select good peers 52 53 // if a peer is marked bad, it will be banned for at least this time period 54 defaultBanTime = 24 * time.Hour 55 ) 56 57 type errMaxAttemptsToDial struct { 58 } 59 60 func (e errMaxAttemptsToDial) Error() string { 61 return fmt.Sprintf("reached max attempts %d to dial", maxAttemptsToDial) 62 } 63 64 type errTooEarlyToDial struct { 65 backoffDuration time.Duration 66 lastDialed time.Time 67 } 68 69 func (e errTooEarlyToDial) Error() string { 70 return fmt.Sprintf( 71 "too early to dial (backoff duration: %d, last dialed: %v, time since: %v)", 72 e.backoffDuration, e.lastDialed, time.Since(e.lastDialed)) 73 } 74 75 // Reactor handles PEX (peer exchange) and ensures that an 76 // adequate number of peers are connected to the switch. 77 // 78 // It uses `AddrBook` (address book) to store `NetAddress`es of the peers. 79 // 80 // ## Preventing abuse 81 // 82 // Only accept pexAddrsMsg from peers we sent a corresponding pexRequestMsg too. 83 // Only accept one pexRequestMsg every ~defaultEnsurePeersPeriod. 84 type Reactor struct { 85 p2p.BaseReactor 86 87 book AddrBook 88 config *ReactorConfig 89 ensurePeersPeriod time.Duration // TODO: should go in the config 90 91 // maps to prevent abuse 92 requestsSent *cmap.CMap // ID->struct{}: unanswered send requests 93 lastReceivedRequests *cmap.CMap // ID->time.Time: last time peer requested from us 94 95 seedAddrs []*p2p.NetAddress 96 97 attemptsToDial sync.Map // address (string) -> {number of attempts (int), last time dialed (time.Time)} 98 99 // seed/crawled mode fields 100 crawlPeerInfos map[p2p.ID]crawlPeerInfo 101 } 102 103 func (r *Reactor) minReceiveRequestInterval() time.Duration { 104 // NOTE: must be less than ensurePeersPeriod, otherwise we'll request 105 // peers too quickly from others and they'll think we're bad! 106 return r.ensurePeersPeriod / 3 107 } 108 109 // ReactorConfig holds reactor specific configuration data. 110 type ReactorConfig struct { 111 // Seed/Crawler mode 112 SeedMode bool 113 114 // We want seeds to only advertise good peers. Therefore they should wait at 115 // least as long as we expect it to take for a peer to become good before 116 // disconnecting. 117 SeedDisconnectWaitPeriod time.Duration 118 119 // Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) 120 PersistentPeersMaxDialPeriod time.Duration 121 122 // Seeds is a list of addresses reactor may use 123 // if it can't connect to peers in the addrbook. 124 Seeds []string 125 } 126 127 type _attemptsToDial struct { 128 number int 129 lastDialed time.Time 130 } 131 132 // NewReactor creates new PEX reactor. 133 func NewReactor(b AddrBook, config *ReactorConfig) *Reactor { 134 r := &Reactor{ 135 book: b, 136 config: config, 137 ensurePeersPeriod: defaultEnsurePeersPeriod, 138 requestsSent: cmap.NewCMap(), 139 lastReceivedRequests: cmap.NewCMap(), 140 crawlPeerInfos: make(map[p2p.ID]crawlPeerInfo), 141 } 142 r.BaseReactor = *p2p.NewBaseReactor("PEX", r) 143 return r 144 } 145 146 // OnStart implements BaseService 147 func (r *Reactor) OnStart() error { 148 err := r.book.Start() 149 if err != nil && err != service.ErrAlreadyStarted { 150 return err 151 } 152 153 numOnline, seedAddrs, err := r.checkSeeds() 154 if err != nil { 155 return err 156 } else if numOnline == 0 && r.book.Empty() { 157 return errors.New("address book is empty and couldn't resolve any seed nodes") 158 } 159 160 r.seedAddrs = seedAddrs 161 162 // Check if this node should run 163 // in seed/crawler mode 164 if r.config.SeedMode { 165 go r.crawlPeersRoutine() 166 } else { 167 go r.ensurePeersRoutine() 168 } 169 return nil 170 } 171 172 // OnStop implements BaseService 173 func (r *Reactor) OnStop() { 174 r.book.Stop() 175 } 176 177 // GetChannels implements Reactor 178 func (r *Reactor) GetChannels() []*conn.ChannelDescriptor { 179 return []*conn.ChannelDescriptor{ 180 { 181 ID: PexChannel, 182 Priority: 1, 183 SendQueueCapacity: 10, 184 RecvMessageCapacity: maxMsgSize, 185 }, 186 } 187 } 188 189 // AddPeer implements Reactor by adding peer to the address book (if inbound) 190 // or by requesting more addresses (if outbound). 191 func (r *Reactor) AddPeer(p Peer) { 192 if p.IsOutbound() { 193 // For outbound peers, the address is already in the books - 194 // either via DialPeersAsync or r.Receive. 195 // Ask it for more peers if we need. 196 if r.book.NeedMoreAddrs() { 197 r.RequestAddrs(p) 198 } 199 } else { 200 // inbound peer is its own source 201 addr, err := p.NodeInfo().NetAddress() 202 if err != nil { 203 r.Logger.Error("Failed to get peer NetAddress", "err", err, "peer", p) 204 return 205 } 206 207 // Make it explicit that addr and src are the same for an inbound peer. 208 src := addr 209 210 // add to book. dont RequestAddrs right away because 211 // we don't trust inbound as much - let ensurePeersRoutine handle it. 212 err = r.book.AddAddress(addr, src) 213 r.logErrAddrBook(err) 214 } 215 } 216 217 // RemovePeer implements Reactor by resetting peer's requests info. 218 func (r *Reactor) RemovePeer(p Peer, reason interface{}) { 219 id := string(p.ID()) 220 r.requestsSent.Delete(id) 221 r.lastReceivedRequests.Delete(id) 222 } 223 224 func (r *Reactor) logErrAddrBook(err error) { 225 if err != nil { 226 switch err.(type) { 227 case ErrAddrBookNilAddr: 228 r.Logger.Error("Failed to add new address", "err", err) 229 default: 230 // non-routable, self, full book, private, etc. 231 r.Logger.Debug("Failed to add new address", "err", err) 232 } 233 } 234 } 235 236 // Receive implements Reactor by handling incoming PEX messages. 237 func (r *Reactor) Receive(chID byte, src Peer, msgBytes []byte) { 238 msg, err := decodeMsg(msgBytes) 239 if err != nil { 240 r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) 241 r.Switch.StopPeerForError(src, err) 242 return 243 } 244 r.Logger.Debug("Received message", "src", src, "chId", chID, "msg", msg) 245 246 switch msg := msg.(type) { 247 case *pexRequestMessage: 248 249 // NOTE: this is a prime candidate for amplification attacks, 250 // so it's important we 251 // 1) restrict how frequently peers can request 252 // 2) limit the output size 253 254 // If we're a seed and this is an inbound peer, 255 // respond once and disconnect. 256 if r.config.SeedMode && !src.IsOutbound() { 257 id := string(src.ID()) 258 v := r.lastReceivedRequests.Get(id) 259 if v != nil { 260 // FlushStop/StopPeer are already 261 // running in a go-routine. 262 return 263 } 264 r.lastReceivedRequests.Set(id, time.Now()) 265 266 // Send addrs and disconnect 267 r.SendAddrs(src, r.book.GetSelectionWithBias(biasToSelectNewPeers)) 268 go func() { 269 // In a go-routine so it doesn't block .Receive. 270 src.FlushStop() 271 r.Switch.StopPeerGracefully(src) 272 }() 273 274 } else { 275 // Check we're not receiving requests too frequently. 276 if err := r.receiveRequest(src); err != nil { 277 r.Switch.StopPeerForError(src, err) 278 r.book.MarkBad(src.SocketAddr(), defaultBanTime) 279 return 280 } 281 r.SendAddrs(src, r.book.GetSelection()) 282 } 283 284 case *pexAddrsMessage: 285 // If we asked for addresses, add them to the book 286 if err := r.ReceiveAddrs(msg.Addrs, src); err != nil { 287 r.Switch.StopPeerForError(src, err) 288 if err == ErrUnsolicitedList { 289 r.book.MarkBad(src.SocketAddr(), defaultBanTime) 290 } 291 return 292 } 293 default: 294 r.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) 295 } 296 } 297 298 // enforces a minimum amount of time between requests 299 func (r *Reactor) receiveRequest(src Peer) error { 300 id := string(src.ID()) 301 v := r.lastReceivedRequests.Get(id) 302 if v == nil { 303 // initialize with empty time 304 lastReceived := time.Time{} 305 r.lastReceivedRequests.Set(id, lastReceived) 306 return nil 307 } 308 309 lastReceived := v.(time.Time) 310 if lastReceived.Equal(time.Time{}) { 311 // first time gets a free pass. then we start tracking the time 312 lastReceived = time.Now() 313 r.lastReceivedRequests.Set(id, lastReceived) 314 return nil 315 } 316 317 now := time.Now() 318 minInterval := r.minReceiveRequestInterval() 319 if now.Sub(lastReceived) < minInterval { 320 return fmt.Errorf( 321 "peer (%v) sent next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting", 322 src.ID(), 323 lastReceived, 324 now, 325 minInterval, 326 ) 327 } 328 r.lastReceivedRequests.Set(id, now) 329 return nil 330 } 331 332 // RequestAddrs asks peer for more addresses if we do not already have a 333 // request out for this peer. 334 func (r *Reactor) RequestAddrs(p Peer) { 335 id := string(p.ID()) 336 if r.requestsSent.Has(id) { 337 return 338 } 339 r.Logger.Debug("Request addrs", "from", p) 340 r.requestsSent.Set(id, struct{}{}) 341 p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexRequestMessage{})) 342 } 343 344 // ReceiveAddrs adds the given addrs to the addrbook if theres an open 345 // request for this peer and deletes the open request. 346 // If there's no open request for the src peer, it returns an error. 347 func (r *Reactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error { 348 id := string(src.ID()) 349 if !r.requestsSent.Has(id) { 350 return ErrUnsolicitedList 351 } 352 r.requestsSent.Delete(id) 353 354 srcAddr, err := src.NodeInfo().NetAddress() 355 if err != nil { 356 return err 357 } 358 359 srcIsSeed := false 360 for _, seedAddr := range r.seedAddrs { 361 if seedAddr.Equals(srcAddr) { 362 srcIsSeed = true 363 break 364 } 365 } 366 367 for _, netAddr := range addrs { 368 // NOTE: we check netAddr validity and routability in book#AddAddress. 369 err = r.book.AddAddress(netAddr, srcAddr) 370 if err != nil { 371 r.logErrAddrBook(err) 372 // XXX: should we be strict about incoming data and disconnect from a 373 // peer here too? 374 continue 375 } 376 377 // If this address came from a seed node, try to connect to it without 378 // waiting (#2093) 379 if srcIsSeed { 380 r.Logger.Info("Will dial address, which came from seed", "addr", netAddr, "seed", srcAddr) 381 go func(addr *p2p.NetAddress) { 382 err := r.dialPeer(addr) 383 if err != nil { 384 switch err.(type) { 385 case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress: 386 r.Logger.Debug(err.Error(), "addr", addr) 387 default: 388 r.Logger.Error(err.Error(), "addr", addr) 389 } 390 } 391 }(netAddr) 392 } 393 } 394 395 return nil 396 } 397 398 // SendAddrs sends addrs to the peer. 399 func (r *Reactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) { 400 p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: netAddrs})) 401 } 402 403 // SetEnsurePeersPeriod sets period to ensure peers connected. 404 func (r *Reactor) SetEnsurePeersPeriod(d time.Duration) { 405 r.ensurePeersPeriod = d 406 } 407 408 // Ensures that sufficient peers are connected. (continuous) 409 func (r *Reactor) ensurePeersRoutine() { 410 var ( 411 seed = tmrand.NewRand() 412 jitter = seed.Int63n(r.ensurePeersPeriod.Nanoseconds()) 413 ) 414 415 // Randomize first round of communication to avoid thundering herd. 416 // If no peers are present directly start connecting so we guarantee swift 417 // setup with the help of configured seeds. 418 if r.nodeHasSomePeersOrDialingAny() { 419 time.Sleep(time.Duration(jitter)) 420 } 421 422 // fire once immediately. 423 // ensures we dial the seeds right away if the book is empty 424 r.ensurePeers() 425 426 // fire periodically 427 ticker := time.NewTicker(r.ensurePeersPeriod) 428 for { 429 select { 430 case <-ticker.C: 431 r.ensurePeers() 432 case <-r.Quit(): 433 ticker.Stop() 434 return 435 } 436 } 437 } 438 439 // ensurePeers ensures that sufficient peers are connected. (once) 440 // 441 // heuristic that we haven't perfected yet, or, perhaps is manually edited by 442 // the node operator. It should not be used to compute what addresses are 443 // already connected or not. 444 func (r *Reactor) ensurePeers() { 445 var ( 446 out, in, dial = r.Switch.NumPeers() 447 numToDial = r.Switch.MaxNumOutboundPeers() - (out + dial) 448 ) 449 r.Logger.Info( 450 "Ensure peers", 451 "numOutPeers", out, 452 "numInPeers", in, 453 "numDialing", dial, 454 "numToDial", numToDial, 455 ) 456 457 if numToDial <= 0 { 458 return 459 } 460 461 // bias to prefer more vetted peers when we have fewer connections. 462 // not perfect, but somewhate ensures that we prioritize connecting to more-vetted 463 // NOTE: range here is [10, 90]. Too high ? 464 newBias := tmmath.MinInt(out, 8)*10 + 10 465 466 toDial := make(map[p2p.ID]*p2p.NetAddress) 467 // Try maxAttempts times to pick numToDial addresses to dial 468 maxAttempts := numToDial * 3 469 470 for i := 0; i < maxAttempts && len(toDial) < numToDial; i++ { 471 try := r.book.PickAddress(newBias) 472 if try == nil { 473 continue 474 } 475 if _, selected := toDial[try.ID]; selected { 476 continue 477 } 478 if r.Switch.IsDialingOrExistingAddress(try) { 479 continue 480 } 481 // TODO: consider moving some checks from toDial into here 482 // so we don't even consider dialing peers that we want to wait 483 // before dialling again, or have dialed too many times already 484 r.Logger.Info("Will dial address", "addr", try) 485 toDial[try.ID] = try 486 } 487 488 // Dial picked addresses 489 for _, addr := range toDial { 490 go func(addr *p2p.NetAddress) { 491 err := r.dialPeer(addr) 492 if err != nil { 493 switch err.(type) { 494 case errMaxAttemptsToDial, errTooEarlyToDial: 495 r.Logger.Debug(err.Error(), "addr", addr) 496 default: 497 r.Logger.Error(err.Error(), "addr", addr) 498 } 499 } 500 }(addr) 501 } 502 503 if r.book.NeedMoreAddrs() { 504 // Check if banned nodes can be reinstated 505 r.book.ReinstateBadPeers() 506 } 507 508 if r.book.NeedMoreAddrs() { 509 510 // 1) Pick a random peer and ask for more. 511 peers := r.Switch.Peers().List() 512 peersCount := len(peers) 513 if peersCount > 0 { 514 peer := peers[tmrand.Int()%peersCount] 515 r.Logger.Info("We need more addresses. Sending pexRequest to random peer", "peer", peer) 516 r.RequestAddrs(peer) 517 } 518 519 // 2) Dial seeds if we are not dialing anyone. 520 // This is done in addition to asking a peer for addresses to work-around 521 // peers not participating in PEX. 522 if len(toDial) == 0 { 523 r.Logger.Info("No addresses to dial. Falling back to seeds") 524 r.dialSeeds() 525 } 526 } 527 } 528 529 func (r *Reactor) dialAttemptsInfo(addr *p2p.NetAddress) (attempts int, lastDialed time.Time) { 530 _attempts, ok := r.attemptsToDial.Load(addr.DialString()) 531 if !ok { 532 return 533 } 534 atd := _attempts.(_attemptsToDial) 535 return atd.number, atd.lastDialed 536 } 537 538 func (r *Reactor) dialPeer(addr *p2p.NetAddress) error { 539 attempts, lastDialed := r.dialAttemptsInfo(addr) 540 if !r.Switch.IsPeerPersistent(addr) && attempts > maxAttemptsToDial { 541 r.book.MarkBad(addr, defaultBanTime) 542 return errMaxAttemptsToDial{} 543 } 544 545 // exponential backoff if it's not our first attempt to dial given address 546 if attempts > 0 { 547 jitter := time.Duration(tmrand.Float64() * float64(time.Second)) // 1s == (1e9 ns) 548 backoffDuration := jitter + ((1 << uint(attempts)) * time.Second) 549 backoffDuration = r.maxBackoffDurationForPeer(addr, backoffDuration) 550 sinceLastDialed := time.Since(lastDialed) 551 if sinceLastDialed < backoffDuration { 552 return errTooEarlyToDial{backoffDuration, lastDialed} 553 } 554 } 555 556 err := r.Switch.DialPeerWithAddress(addr) 557 if err != nil { 558 if _, ok := err.(p2p.ErrCurrentlyDialingOrExistingAddress); ok { 559 return err 560 } 561 562 markAddrInBookBasedOnErr(addr, r.book, err) 563 switch err.(type) { 564 case p2p.ErrSwitchAuthenticationFailure: 565 // NOTE: addr is removed from addrbook in markAddrInBookBasedOnErr 566 r.attemptsToDial.Delete(addr.DialString()) 567 default: 568 r.attemptsToDial.Store(addr.DialString(), _attemptsToDial{attempts + 1, time.Now()}) 569 } 570 return fmt.Errorf("dialing failed (attempts: %d): %w", attempts+1, err) 571 } 572 573 // cleanup any history 574 r.attemptsToDial.Delete(addr.DialString()) 575 return nil 576 } 577 578 // maxBackoffDurationForPeer caps the backoff duration for persistent peers. 579 func (r *Reactor) maxBackoffDurationForPeer(addr *p2p.NetAddress, planned time.Duration) time.Duration { 580 if r.config.PersistentPeersMaxDialPeriod > 0 && 581 planned > r.config.PersistentPeersMaxDialPeriod && 582 r.Switch.IsPeerPersistent(addr) { 583 return r.config.PersistentPeersMaxDialPeriod 584 } 585 return planned 586 } 587 588 // checkSeeds checks that addresses are well formed. 589 // Returns number of seeds we can connect to, along with all seeds addrs. 590 // return err if user provided any badly formatted seed addresses. 591 // Doesn't error if the seed node can't be reached. 592 // numOnline returns -1 if no seed nodes were in the initial configuration. 593 func (r *Reactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, err error) { 594 lSeeds := len(r.config.Seeds) 595 if lSeeds == 0 { 596 return -1, nil, nil 597 } 598 netAddrs, errs := p2p.NewNetAddressStrings(r.config.Seeds) 599 numOnline = lSeeds - len(errs) 600 for _, err := range errs { 601 switch e := err.(type) { 602 case p2p.ErrNetAddressLookup: 603 r.Logger.Error("Connecting to seed failed", "err", e) 604 default: 605 return 0, nil, fmt.Errorf("seed node configuration has error: %w", e) 606 } 607 } 608 return numOnline, netAddrs, nil 609 } 610 611 // randomly dial seeds until we connect to one or exhaust them 612 func (r *Reactor) dialSeeds() { 613 perm := tmrand.Perm(len(r.seedAddrs)) 614 // perm := r.Switch.rng.Perm(lSeeds) 615 for _, i := range perm { 616 // dial a random seed 617 seedAddr := r.seedAddrs[i] 618 err := r.Switch.DialPeerWithAddress(seedAddr) 619 620 switch err.(type) { 621 case nil, p2p.ErrCurrentlyDialingOrExistingAddress: 622 return 623 } 624 r.Switch.Logger.Error("Error dialing seed", "err", err, "seed", seedAddr) 625 } 626 // do not write error message if there were no seeds specified in config 627 if len(r.seedAddrs) > 0 { 628 r.Switch.Logger.Error("Couldn't connect to any seeds") 629 } 630 } 631 632 // AttemptsToDial returns the number of attempts to dial specific address. It 633 // returns 0 if never attempted or successfully connected. 634 func (r *Reactor) AttemptsToDial(addr *p2p.NetAddress) int { 635 lAttempts, attempted := r.attemptsToDial.Load(addr.DialString()) 636 if attempted { 637 return lAttempts.(_attemptsToDial).number 638 } 639 return 0 640 } 641 642 //---------------------------------------------------------- 643 644 // Explores the network searching for more peers. (continuous) 645 // Seed/Crawler Mode causes this node to quickly disconnect 646 // from peers, except other seed nodes. 647 func (r *Reactor) crawlPeersRoutine() { 648 // If we have any seed nodes, consult them first 649 if len(r.seedAddrs) > 0 { 650 r.dialSeeds() 651 } else { 652 // Do an initial crawl 653 r.crawlPeers(r.book.GetSelection()) 654 } 655 656 // Fire periodically 657 ticker := time.NewTicker(crawlPeerPeriod) 658 659 for { 660 select { 661 case <-ticker.C: 662 r.attemptDisconnects() 663 r.crawlPeers(r.book.GetSelection()) 664 r.cleanupCrawlPeerInfos() 665 case <-r.Quit(): 666 return 667 } 668 } 669 } 670 671 // nodeHasSomePeersOrDialingAny returns true if the node is connected to some 672 // peers or dialing them currently. 673 func (r *Reactor) nodeHasSomePeersOrDialingAny() bool { 674 out, in, dial := r.Switch.NumPeers() 675 return out+in+dial > 0 676 } 677 678 // crawlPeerInfo handles temporary data needed for the network crawling 679 // performed during seed/crawler mode. 680 type crawlPeerInfo struct { 681 Addr *p2p.NetAddress `json:"addr"` 682 // The last time we crawled the peer or attempted to do so. 683 LastCrawled time.Time `json:"last_crawled"` 684 } 685 686 // crawlPeers will crawl the network looking for new peer addresses. 687 func (r *Reactor) crawlPeers(addrs []*p2p.NetAddress) { 688 now := time.Now() 689 690 for _, addr := range addrs { 691 peerInfo, ok := r.crawlPeerInfos[addr.ID] 692 693 // Do not attempt to connect with peers we recently crawled. 694 if ok && now.Sub(peerInfo.LastCrawled) < minTimeBetweenCrawls { 695 continue 696 } 697 698 // Record crawling attempt. 699 r.crawlPeerInfos[addr.ID] = crawlPeerInfo{ 700 Addr: addr, 701 LastCrawled: now, 702 } 703 704 err := r.dialPeer(addr) 705 if err != nil { 706 switch err.(type) { 707 case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress: 708 r.Logger.Debug(err.Error(), "addr", addr) 709 default: 710 r.Logger.Error(err.Error(), "addr", addr) 711 } 712 continue 713 } 714 715 peer := r.Switch.Peers().Get(addr.ID) 716 if peer != nil { 717 r.RequestAddrs(peer) 718 } 719 } 720 } 721 722 func (r *Reactor) cleanupCrawlPeerInfos() { 723 for id, info := range r.crawlPeerInfos { 724 // If we did not crawl a peer for 24 hours, it means the peer was removed 725 // from the addrbook => remove 726 // 727 // 10000 addresses / maxGetSelection = 40 cycles to get all addresses in 728 // the ideal case, 729 // 40 * crawlPeerPeriod ~ 20 minutes 730 if time.Since(info.LastCrawled) > 24*time.Hour { 731 delete(r.crawlPeerInfos, id) 732 } 733 } 734 } 735 736 // attemptDisconnects checks if we've been with each peer long enough to disconnect 737 func (r *Reactor) attemptDisconnects() { 738 for _, peer := range r.Switch.Peers().List() { 739 if peer.Status().Duration < r.config.SeedDisconnectWaitPeriod { 740 continue 741 } 742 if peer.IsPersistent() { 743 continue 744 } 745 r.Switch.StopPeerGracefully(peer) 746 } 747 } 748 749 func markAddrInBookBasedOnErr(addr *p2p.NetAddress, book AddrBook, err error) { 750 // TODO: detect more "bad peer" scenarios 751 switch err.(type) { 752 case p2p.ErrSwitchAuthenticationFailure: 753 book.MarkBad(addr, defaultBanTime) 754 default: 755 book.MarkAttempt(addr) 756 } 757 } 758 759 //----------------------------------------------------------------------------- 760 // Messages 761 762 // Message is a primary type for PEX messages. Underneath, it could contain 763 // either pexRequestMessage, or pexAddrsMessage messages. 764 type Message interface{} 765 766 func RegisterMessages(cdc *amino.Codec) { 767 cdc.RegisterInterface((*Message)(nil), nil) 768 cdc.RegisterConcrete(&pexRequestMessage{}, "tendermint/p2p/PexRequestMessage", nil) 769 cdc.RegisterConcrete(&pexAddrsMessage{}, "tendermint/p2p/PexAddrsMessage", nil) 770 } 771 772 func decodeMsg(bz []byte) (msg Message, err error) { 773 err = cdc.UnmarshalBinaryBare(bz, &msg) 774 return 775 } 776 777 /* 778 A pexRequestMessage requests additional peer addresses. 779 */ 780 type pexRequestMessage struct { 781 } 782 783 func (m *pexRequestMessage) String() string { 784 return "[pexRequest]" 785 } 786 787 /* 788 A message with announced peer addresses. 789 */ 790 type pexAddrsMessage struct { 791 Addrs []*p2p.NetAddress 792 } 793 794 func (m *pexAddrsMessage) String() string { 795 return fmt.Sprintf("[pexAddrs %v]", m.Addrs) 796 }