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