git.gammaspectra.live/P2Pool/consensus/v3@v3.8.0/p2pool/p2p/server.go (about) 1 package p2p 2 3 import ( 4 "context" 5 "crypto/rand" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "git.gammaspectra.live/P2Pool/consensus/v3/monero/client" 10 "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/mainchain" 11 "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/sidechain" 12 p2pooltypes "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/types" 13 "git.gammaspectra.live/P2Pool/consensus/v3/types" 14 "git.gammaspectra.live/P2Pool/consensus/v3/utils" 15 unsafeRandom "math/rand/v2" 16 "net" 17 "net/netip" 18 "slices" 19 "sync" 20 "sync/atomic" 21 "time" 22 "unsafe" 23 ) 24 25 type P2PoolInterface interface { 26 sidechain.ConsensusProvider 27 SideChain() *sidechain.SideChain 28 MainChain() *mainchain.MainChain 29 GetChainMainTip() *sidechain.ChainMain 30 GetMinerDataTip() *p2pooltypes.MinerData 31 ClientRPC() *client.Client 32 } 33 34 type PeerListEntry struct { 35 AddressPort netip.AddrPort 36 FailedConnections atomic.Uint32 37 LastSeenTimestamp atomic.Uint64 38 } 39 40 type PeerList []*PeerListEntry 41 42 func (l PeerList) Get(addr netip.Addr) *PeerListEntry { 43 if i := slices.IndexFunc(l, func(entry *PeerListEntry) bool { 44 return entry.AddressPort.Addr().Compare(addr) == 0 45 }); i != -1 { 46 return l[i] 47 } 48 return nil 49 } 50 func (l PeerList) Delete(addr netip.Addr) PeerList { 51 ret := l 52 for i := slices.IndexFunc(ret, func(entry *PeerListEntry) bool { 53 return entry.AddressPort.Addr().Compare(addr) == 0 54 }); i != -1; i = slices.IndexFunc(ret, func(entry *PeerListEntry) bool { 55 return entry.AddressPort.Addr().Compare(addr) == 0 56 }) { 57 ret = slices.Delete(ret, i, i+1) 58 } 59 return ret 60 } 61 62 type BanEntry struct { 63 Expiration uint64 64 Error error 65 } 66 67 type Server struct { 68 p2pool P2PoolInterface 69 70 peerId uint64 71 versionInformation p2pooltypes.PeerVersionInformation 72 73 listenAddress netip.AddrPort 74 externalListenPort uint16 75 76 useIPv4 bool 77 useIPv6 bool 78 79 ipv6AddrsLock sync.RWMutex 80 ipv6OutgoingAddresses []netip.Addr 81 82 close atomic.Bool 83 listener *net.TCPListener 84 85 fastestPeer *Client 86 87 MaxOutgoingPeers uint32 88 MaxIncomingPeers uint32 89 90 NumOutgoingConnections atomic.Int32 91 NumIncomingConnections atomic.Int32 92 93 PendingOutgoingConnections *utils.CircularBuffer[string] 94 95 peerList PeerList 96 peerListLock sync.RWMutex 97 moneroPeerList PeerList 98 99 bansLock sync.RWMutex 100 bans map[[16]byte]BanEntry 101 102 clientsLock sync.RWMutex 103 clients []*Client 104 105 cachedBlocksLock sync.RWMutex 106 cachedBlocks map[types.Hash]*sidechain.PoolBlock 107 108 ctx context.Context 109 } 110 111 func NewServer(p2pool P2PoolInterface, listenAddress string, externalListenPort uint16, maxOutgoingPeers, maxIncomingPeers uint32, useIPv4, useIPv6 bool, ctx context.Context) (*Server, error) { 112 peerId := make([]byte, int(unsafe.Sizeof(uint64(0)))) 113 _, err := rand.Read(peerId) 114 if err != nil { 115 return nil, err 116 } 117 118 addrPort, err := netip.ParseAddrPort(listenAddress) 119 if err != nil { 120 return nil, err 121 } 122 123 s := &Server{ 124 p2pool: p2pool, 125 listenAddress: addrPort, 126 externalListenPort: externalListenPort, 127 peerId: binary.LittleEndian.Uint64(peerId), 128 MaxOutgoingPeers: min(maxOutgoingPeers, 450), 129 MaxIncomingPeers: min(maxIncomingPeers, 450), 130 cachedBlocks: make(map[types.Hash]*sidechain.PoolBlock, p2pool.Consensus().ChainWindowSize*3), 131 versionInformation: p2pooltypes.PeerVersionInformation{ 132 SoftwareId: p2pooltypes.CurrentSoftwareId, 133 SoftwareVersion: p2pooltypes.CurrentSoftwareVersion, 134 Protocol: p2pooltypes.SupportedProtocolVersion, 135 }, 136 useIPv4: useIPv4, 137 useIPv6: useIPv6, 138 ctx: ctx, 139 bans: make(map[[16]byte]BanEntry), 140 } 141 142 s.PendingOutgoingConnections = utils.NewCircularBuffer[string](int(s.MaxOutgoingPeers)) 143 s.RefreshOutgoingIPv6() 144 145 return s, nil 146 } 147 148 func (s *Server) RefreshOutgoingIPv6() { 149 utils.Logf("P2PServer", "Refreshing outgoing IPv6") 150 addrs, _ := utils.GetOutboundIPv6() 151 s.ipv6AddrsLock.Lock() 152 defer s.ipv6AddrsLock.Unlock() 153 s.ipv6OutgoingAddresses = addrs 154 for _, a := range addrs { 155 utils.Logf("P2PServer", "Outgoing IPv6: %s", a.String()) 156 } 157 } 158 159 func (s *Server) GetOutgoingIPv6() []netip.Addr { 160 s.ipv6AddrsLock.RLock() 161 defer s.ipv6AddrsLock.RUnlock() 162 return s.ipv6OutgoingAddresses 163 } 164 165 func (s *Server) ListenPort() uint16 { 166 return s.listenAddress.Port() 167 } 168 169 func (s *Server) ExternalListenPort() uint16 { 170 if s.externalListenPort != 0 { 171 return s.externalListenPort 172 } else { 173 return s.listenAddress.Port() 174 } 175 } 176 177 func (s *Server) AddToPeerList(addressPort netip.AddrPort) { 178 if addressPort.Addr().IsLoopback() { 179 return 180 } 181 addr := addressPort.Addr().Unmap() 182 183 if !s.useIPv4 && addr.Is4() { 184 return 185 } else if !s.useIPv6 && addr.Is6() { 186 return 187 } 188 189 s.peerListLock.Lock() 190 defer s.peerListLock.Unlock() 191 if e := s.peerList.Get(addr); e == nil { 192 if ok, _ := s.IsBanned(addr); ok { 193 return 194 } 195 e = &PeerListEntry{ 196 AddressPort: netip.AddrPortFrom(addr, addressPort.Port()), 197 } 198 e.LastSeenTimestamp.Store(uint64(time.Now().Unix())) 199 s.peerList = append(s.peerList, e) 200 } else { 201 e.LastSeenTimestamp.Store(uint64(time.Now().Unix())) 202 } 203 } 204 205 func (s *Server) UpdateInPeerList(addressPort netip.AddrPort) { 206 if addressPort.Addr().IsLoopback() { 207 return 208 } 209 addr := addressPort.Addr().Unmap() 210 211 if !s.useIPv4 && addr.Is4() { 212 return 213 } else if !s.useIPv6 && addr.Is6() { 214 return 215 } 216 s.peerListLock.Lock() 217 defer s.peerListLock.Unlock() 218 if e := s.peerList.Get(addr); e == nil { 219 if ok, _ := s.IsBanned(addr); ok { 220 return 221 } 222 e = &PeerListEntry{ 223 AddressPort: netip.AddrPortFrom(addr, addressPort.Port()), 224 } 225 e.LastSeenTimestamp.Store(uint64(time.Now().Unix())) 226 s.peerList = append(s.peerList, e) 227 } else { 228 e.FailedConnections.Store(0) 229 e.LastSeenTimestamp.Store(uint64(time.Now().Unix())) 230 } 231 } 232 233 func (s *Server) PeerList() PeerList { 234 s.peerListLock.RLock() 235 defer s.peerListLock.RUnlock() 236 237 return slices.Clone(s.peerList) 238 } 239 240 func (s *Server) RemoveFromPeerList(ip netip.Addr) { 241 ip = ip.Unmap() 242 s.peerListLock.Lock() 243 defer s.peerListLock.Unlock() 244 for i := len(s.peerList) - 1; i >= 0; i-- { 245 a := s.peerList[i] 246 if a.AddressPort.Addr().Compare(ip) == 0 { 247 s.peerList = slices.Delete(s.peerList, i, i+1) 248 return 249 } 250 } 251 } 252 253 func (s *Server) GetFastestClient() *Client { 254 var client *Client 255 var ping uint64 256 for _, c := range s.Clients() { 257 p := c.PingDuration.Load() 258 if c.IsGood() && p != 0 && (ping == 0 || p < ping) { 259 client = c 260 ping = p 261 } 262 } 263 264 return client 265 } 266 267 func (s *Server) UpdatePeerList() { 268 curTime := uint64(time.Now().Unix()) 269 for _, c := range s.Clients() { 270 if c.IsGood() && curTime >= c.NextOutgoingPeerListRequestTimestamp.Load() { 271 c.SendPeerListRequest() 272 } 273 } 274 } 275 276 func (s *Server) CleanupBanList() { 277 s.bansLock.Lock() 278 defer s.bansLock.Unlock() 279 280 currentTime := uint64(time.Now().Unix()) 281 282 for k, b := range s.bans { 283 if currentTime >= b.Expiration { 284 delete(s.bans, k) 285 } 286 } 287 } 288 289 func (s *Server) UpdateClientConnections() { 290 291 currentTime := uint64(time.Now().Unix()) 292 lastUpdated := uint64(s.SideChain().LastUpdated().Unix()) 293 294 var hasGoodPeers bool 295 var fastestPeer *Client 296 297 connectedClients := s.Clients() 298 299 connectedPeers := make([]netip.Addr, 0, len(connectedClients)) 300 301 for _, client := range connectedClients { 302 timeout := uint64(10) 303 if client.HandshakeComplete.Load() { 304 timeout = 300 305 } 306 307 lastAlive := client.LastActiveTimestamp.Load() 308 309 if currentTime >= (lastAlive + timeout) { 310 idleTime := currentTime - lastAlive 311 utils.Logf("P2PServer", "peer %s has been idle for %d seconds, disconnecting", client.AddressPort, idleTime) 312 client.Close() 313 continue 314 } 315 316 if client.HandshakeComplete.Load() && client.LastBroadcastTimestamp.Load() > 0 { 317 // - Side chain is at least 15 minutes newer (last_updated >= client->m_lastBroadcastTimestamp + 900) 318 // - It's been at least 10 seconds since side chain updated (cur_time >= last_updated + 10) 319 // - It's been at least 10 seconds since the last block request (peer is not syncing) 320 // - Peer should have sent a broadcast by now 321 322 if lastUpdated > 0 && (currentTime >= max(lastUpdated, client.LastBlockRequestTimestamp.Load())+10) && (lastUpdated >= client.LastBroadcastTimestamp.Load()+900) { 323 dt := lastUpdated - client.LastBroadcastTimestamp.Load() 324 client.Ban(DefaultBanTime, fmt.Errorf("not broadcasting blocks (last update %d seconds ago)", dt)) 325 client.Close() 326 continue 327 } 328 } 329 330 connectedPeers = append(connectedPeers, client.AddressPort.Addr().Unmap()) 331 if client.IsGood() { 332 hasGoodPeers = true 333 if client.PingDuration.Load() >= 0 && (fastestPeer == nil || fastestPeer.PingDuration.Load() > client.PingDuration.Load()) { 334 fastestPeer = client 335 } 336 } 337 } 338 339 deletedPeers := 0 340 peerList := s.PeerList() 341 peerList2 := slices.Clone(peerList) 342 for _, p := range peerList { 343 if slices.ContainsFunc(connectedPeers, func(addr netip.Addr) bool { 344 return p.AddressPort.Addr().Compare(addr) == 0 345 }) { 346 p.LastSeenTimestamp.Store(currentTime) 347 } 348 if (p.LastSeenTimestamp.Load() + 3600) < currentTime { 349 peerList2 = peerList2.Delete(p.AddressPort.Addr()) 350 deletedPeers++ 351 } 352 } 353 peerList = peerList2 354 355 if deletedPeers > 0 { 356 func() { 357 s.peerListLock.Lock() 358 defer s.peerListLock.Unlock() 359 s.peerList = slices.Clone(peerList) 360 }() 361 } 362 363 N := int(s.MaxOutgoingPeers) 364 365 // Special case: when we can't find p2pool peers, scan through monerod peers (try 25 peers at a time) 366 if !hasGoodPeers && len(s.moneroPeerList) > 0 { 367 utils.Logf("P2PServer", "Scanning monerod peers, %d left", len(s.moneroPeerList)) 368 for i := 0; i < 25 && len(s.moneroPeerList) > 0; i++ { 369 peerList = append(peerList, s.moneroPeerList[len(s.moneroPeerList)-1]) 370 s.moneroPeerList = s.moneroPeerList[:len(s.moneroPeerList)-1] 371 } 372 N = len(peerList) 373 } 374 375 var wg sync.WaitGroup 376 attempts := 0 377 378 for i := s.NumOutgoingConnections.Load() - s.NumIncomingConnections.Load(); int(i) < N && len(peerList) > 0; { 379 k := unsafeRandom.IntN(len(peerList)) % len(peerList) 380 peer := peerList[k] 381 382 if !slices.ContainsFunc(connectedPeers, func(addr netip.Addr) bool { 383 return peer.AddressPort.Addr().Compare(addr) == 0 384 }) { 385 wg.Add(1) 386 attempts++ 387 go func() { 388 defer wg.Done() 389 390 if s.NumOutgoingConnections.Load() >= int32(s.MaxOutgoingPeers) { 391 return 392 } 393 if err := s.Connect(peer.AddressPort); err != nil { 394 utils.Logf("P2PServer", "Connection to %s rejected (%s)", peer.AddressPort.String(), err.Error()) 395 } 396 }() 397 i++ 398 } 399 400 peerList = slices.Delete(peerList, k, k+1) 401 } 402 403 wg.Wait() 404 405 if attempts == 0 && !hasGoodPeers && len(s.moneroPeerList) == 0 { 406 utils.Logf("P2PServer", "No connections to other p2pool nodes, check your monerod/p2pool/network/firewall setup!") 407 if moneroPeerList, err := s.p2pool.ClientRPC().GetPeerList(); err == nil { 408 s.moneroPeerList = make(PeerList, 0, len(moneroPeerList.WhiteList)) 409 for _, p := range moneroPeerList.WhiteList { 410 addr, err := netip.ParseAddr(p.Host) 411 if err != nil { 412 continue 413 } 414 e := &PeerListEntry{ 415 AddressPort: netip.AddrPortFrom(addr, s.Consensus().DefaultPort()), 416 } 417 e.LastSeenTimestamp.Store(uint64(p.LastSeen)) 418 if ok, _ := s.IsBanned(addr); !ok { 419 if !s.useIPv4 && addr.Is4() { 420 continue 421 } else if !s.useIPv6 && addr.Is6() { 422 continue 423 } 424 s.moneroPeerList = append(s.moneroPeerList, e) 425 } 426 } 427 slices.SortFunc(s.moneroPeerList, func(a, b *PeerListEntry) int { 428 aValue, bValue := a.LastSeenTimestamp.Load(), b.LastSeenTimestamp.Load() 429 if aValue < bValue { 430 return -1 431 } else if aValue > bValue { 432 return 1 433 } 434 return 0 435 }) 436 utils.Logf("P2PServer", "monerod peer list loaded (%d peers)", len(s.moneroPeerList)) 437 } 438 } 439 } 440 441 func (s *Server) AddCachedBlock(block *sidechain.PoolBlock) { 442 s.cachedBlocksLock.Lock() 443 defer s.cachedBlocksLock.Unlock() 444 445 if s.cachedBlocks == nil { 446 return 447 } 448 449 s.cachedBlocks[block.SideTemplateId(s.p2pool.Consensus())] = block 450 } 451 452 func (s *Server) ClearCachedBlocks() { 453 s.cachedBlocksLock.Lock() 454 defer s.cachedBlocksLock.Unlock() 455 456 s.cachedBlocks = nil 457 } 458 459 func (s *Server) GetCachedBlock(hash types.Hash) *sidechain.PoolBlock { 460 s.cachedBlocksLock.RLock() 461 defer s.cachedBlocksLock.RUnlock() 462 463 return s.cachedBlocks[hash] 464 } 465 466 func (s *Server) DownloadMissingBlocks() { 467 clientList := s.Clients() 468 469 if len(clientList) == 0 { 470 return 471 } 472 473 s.cachedBlocksLock.RLock() 474 defer s.cachedBlocksLock.RUnlock() 475 476 for { 477 obtained := false 478 for _, h := range s.SideChain().GetMissingBlocks() { 479 if b, ok := s.cachedBlocks[h]; ok { 480 if _, err, _ := s.SideChain().AddPoolBlockExternal(b); err == nil { 481 obtained = true 482 continue 483 } 484 } 485 486 clientList[unsafeRandom.IntN(len(clientList))].SendUniqueBlockRequest(h) 487 } 488 if !obtained { 489 break 490 } 491 } 492 } 493 494 func (s *Server) Listen() (err error) { 495 var listener net.Listener 496 var ok bool 497 if listener, err = (&net.ListenConfig{}).Listen(s.ctx, "tcp", s.listenAddress.String()); err != nil { 498 return err 499 } else if s.listener, ok = listener.(*net.TCPListener); !ok { 500 return errors.New("not a tcp listener") 501 } else { 502 defer s.listener.Close() 503 504 var wg sync.WaitGroup 505 wg.Add(1) 506 go func() { 507 defer wg.Done() 508 for range utils.ContextTick(s.ctx, time.Second*5) { 509 s.UpdatePeerList() 510 s.UpdateClientConnections() 511 } 512 }() 513 wg.Add(1) 514 go func() { 515 defer wg.Done() 516 for range utils.ContextTick(s.ctx, time.Second) { 517 if s.SideChain().PreCalcFinished() { 518 s.ClearCachedBlocks() 519 break 520 } 521 522 s.DownloadMissingBlocks() 523 } 524 // Slow down updates for missing blocks after sync 525 for range utils.ContextTick(s.ctx, time.Minute*2) { 526 s.DownloadMissingBlocks() 527 } 528 }() 529 wg.Add(1) 530 go func() { 531 defer wg.Done() 532 for range utils.ContextTick(s.ctx, time.Hour) { 533 s.RefreshOutgoingIPv6() 534 } 535 }() 536 wg.Add(1) 537 go func() { 538 defer wg.Done() 539 for range utils.ContextTick(s.ctx, time.Minute*5) { 540 s.CleanupBanList() 541 } 542 }() 543 544 for !s.close.Load() { 545 if conn, err := s.listener.AcceptTCP(); err != nil { 546 return err 547 } else { 548 if err = func() error { 549 if uint32(s.NumIncomingConnections.Load()) > s.MaxIncomingPeers { 550 return errors.New("incoming connections limit was reached") 551 } 552 if addrPort, err := netip.ParseAddrPort(conn.RemoteAddr().String()); err != nil { 553 return err 554 } else if !addrPort.Addr().IsLoopback() { 555 if clients := s.GetAddressConnected(addrPort.Addr()); !addrPort.Addr().IsLoopback() && len(clients) != 0 { 556 return errors.New("peer is already connected as " + clients[0].AddressPort.String()) 557 } 558 559 addr := addrPort.Addr().Unmap() 560 561 if !s.useIPv4 && addr.Is4() { 562 return errors.New("peer is IPv4 but we do not allow it") 563 } else if !s.useIPv6 && addr.Is6() { 564 return errors.New("peer is IPv6 but we do not allow it") 565 } 566 567 if ok, b := s.IsBanned(addr); ok { 568 return fmt.Errorf("peer is banned: %w", b.Error) 569 } 570 } 571 572 return nil 573 }(); err != nil { 574 go func() { 575 defer conn.Close() 576 utils.Logf("P2PServer", "Connection from %s rejected (%s)", conn.RemoteAddr().String(), err.Error()) 577 }() 578 continue 579 } 580 581 func() { 582 utils.Logf("P2PServer", "Incoming connection from %s", conn.RemoteAddr().String()) 583 584 s.clientsLock.Lock() 585 defer s.clientsLock.Unlock() 586 client := NewClient(s, conn) 587 client.IsIncomingConnection = true 588 s.clients = append(s.clients, client) 589 s.NumIncomingConnections.Add(1) 590 go client.OnConnection() 591 }() 592 } 593 594 } 595 596 wg.Wait() 597 } 598 599 return nil 600 } 601 602 func (s *Server) GetAddressConnectedPrefix(prefix netip.Prefix) (result []*Client) { 603 s.clientsLock.RLock() 604 defer s.clientsLock.RUnlock() 605 for _, c := range s.clients { 606 if prefix.Contains(c.AddressPort.Addr()) { 607 result = append(result, c) 608 } 609 } 610 return result 611 } 612 613 func (s *Server) GetAddressConnected(addr netip.Addr) (result []*Client) { 614 s.clientsLock.RLock() 615 defer s.clientsLock.RUnlock() 616 for _, c := range s.clients { 617 if c.AddressPort.Addr().Compare(addr) == 0 { 618 result = append(result, c) 619 } 620 } 621 return result 622 } 623 624 func (s *Server) DirectConnect(addrPort netip.AddrPort) (*Client, error) { 625 addr := addrPort.Addr().Unmap() 626 if !s.useIPv4 && addr.Is4() { 627 return nil, errors.New("peer is IPv4 but we do not allow it") 628 } else if !s.useIPv6 && addr.Is6() { 629 return nil, errors.New("peer is IPv6 but we do not allow it") 630 } 631 632 if clients := s.GetAddressConnected(addrPort.Addr()); !addrPort.Addr().IsLoopback() && len(clients) != 0 { 633 return nil, errors.New("peer is already connected as " + clients[0].AddressPort.String()) 634 } 635 636 if !s.PendingOutgoingConnections.PushUnique(addrPort.Addr().String()) { 637 return nil, errors.New("peer is already attempting connection") 638 } 639 640 s.NumOutgoingConnections.Add(1) 641 642 var localAddr net.Addr 643 644 //select IPv6 outgoing address 645 if addr.Is6() { 646 addrs := s.GetOutgoingIPv6() 647 if len(addrs) > 1 { 648 a := addrs[unsafeRandom.IntN(len(addrs))] 649 localAddr = &net.TCPAddr{IP: a.AsSlice(), Zone: a.Zone()} 650 } else if len(addrs) == 1 { 651 localAddr = &net.TCPAddr{IP: addrs[0].AsSlice(), Zone: addrs[0].Zone()} 652 } 653 } 654 655 if localAddr != nil { 656 utils.Logf("P2PServer", "Outgoing connection to %s using %s", addrPort.String(), localAddr.String()) 657 } else { 658 utils.Logf("P2PServer", "Outgoing connection to %s", addrPort.String()) 659 } 660 661 if conn, err := (&net.Dialer{Timeout: time.Second * 5, LocalAddr: localAddr}).DialContext(s.ctx, "tcp", addrPort.String()); err != nil { 662 s.NumOutgoingConnections.Add(-1) 663 s.PendingOutgoingConnections.Replace(addrPort.Addr().String(), "") 664 if p := s.PeerList().Get(addrPort.Addr()); p != nil { 665 if p.FailedConnections.Add(1) >= 10 { 666 s.RemoveFromPeerList(addrPort.Addr()) 667 } 668 } 669 return nil, err 670 } else if tcpConn, ok := conn.(*net.TCPConn); !ok { 671 s.NumOutgoingConnections.Add(-1) 672 s.PendingOutgoingConnections.Replace(addrPort.Addr().String(), "") 673 if p := s.PeerList().Get(addrPort.Addr()); p != nil { 674 if p.FailedConnections.Add(1) >= 10 { 675 s.RemoveFromPeerList(addrPort.Addr()) 676 } 677 } 678 return nil, errors.New("not a tcp connection") 679 } else { 680 s.clientsLock.Lock() 681 defer s.clientsLock.Unlock() 682 client := NewClient(s, tcpConn) 683 s.clients = append(s.clients, client) 684 go client.OnConnection() 685 return client, nil 686 } 687 } 688 689 func (s *Server) Connect(addrPort netip.AddrPort) error { 690 if ok, b := s.IsBanned(addrPort.Addr()); ok { 691 return fmt.Errorf("peer is banned: %w", b.Error) 692 } 693 694 _, err := s.DirectConnect(addrPort) 695 return err 696 } 697 698 func (s *Server) Clients() []*Client { 699 s.clientsLock.RLock() 700 defer s.clientsLock.RUnlock() 701 return slices.Clone(s.clients) 702 } 703 704 func (s *Server) IsBanned(ip netip.Addr) (bool, *BanEntry) { 705 if ip.IsLoopback() { 706 return false, nil 707 } 708 ip = ip.Unmap() 709 var prefix netip.Prefix 710 if ip.Is6() { 711 //ban the /64 712 prefix, _ = ip.Prefix(64) 713 } else if ip.Is4() { 714 //ban only a single ip, /32 715 prefix, _ = ip.Prefix(32) 716 } 717 718 if !prefix.IsValid() { 719 return false, nil 720 } 721 722 k := prefix.Addr().As16() 723 724 if b, ok := func() (entry BanEntry, ok bool) { 725 s.bansLock.RLock() 726 defer s.bansLock.RUnlock() 727 entry, ok = s.bans[k] 728 return entry, ok 729 }(); ok == false { 730 return false, nil 731 } else if uint64(time.Now().Unix()) >= b.Expiration { 732 return false, nil 733 } else { 734 return true, &b 735 } 736 } 737 738 func (s *Server) Ban(ip netip.Addr, duration time.Duration, err error) { 739 if ok, _ := s.IsBanned(ip); ok { 740 return 741 } 742 743 utils.Logf("P2PServer", "Banned %s for %s: %s", ip.String(), duration.String(), err.Error()) 744 if !ip.IsLoopback() { 745 ip = ip.Unmap() 746 var prefix netip.Prefix 747 if ip.Is6() { 748 //ban the /64 749 prefix, _ = ip.Prefix(64) 750 } else if ip.Is4() { 751 //ban only a single ip, /32 752 prefix, _ = ip.Prefix(32) 753 } 754 755 if prefix.IsValid() { 756 func() { 757 s.bansLock.Lock() 758 defer s.bansLock.Unlock() 759 s.bans[prefix.Addr().As16()] = BanEntry{ 760 Error: err, 761 Expiration: uint64(time.Now().Unix()) + uint64(duration.Seconds()), 762 } 763 }() 764 for _, c := range s.GetAddressConnectedPrefix(prefix) { 765 c.Close() 766 } 767 } 768 } 769 770 } 771 772 func (s *Server) Close() { 773 if !s.close.Swap(true) && s.listener != nil { 774 s.clientsLock.Lock() 775 defer s.clientsLock.Unlock() 776 for _, c := range s.clients { 777 c.Connection.Close() 778 } 779 s.listener.Close() 780 } 781 } 782 783 func (s *Server) VersionInformation() *p2pooltypes.PeerVersionInformation { 784 return &s.versionInformation 785 } 786 787 func (s *Server) PeerId() uint64 { 788 return s.peerId 789 } 790 791 func (s *Server) SideChain() *sidechain.SideChain { 792 return s.p2pool.SideChain() 793 } 794 795 func (s *Server) MainChain() *mainchain.MainChain { 796 return s.p2pool.MainChain() 797 } 798 799 func (s *Server) Broadcast(block *sidechain.PoolBlock) { 800 var message, prunedMessage, compactMessage *ClientMessage 801 if block != nil { 802 // Full block broadcast 803 buffer := make([]byte, 4, block.BufferLength()+4) 804 blockData, err := block.AppendBinaryFlags(buffer, false, false) 805 if err != nil { 806 utils.Panicf("[P2PServer] Tried to broadcast block %s at height %d but received error: %s", block.SideTemplateId(s.Consensus()), block.Side.Height, err) 807 return 808 } 809 binary.LittleEndian.PutUint32(blockData, uint32(len(blockData)-4)) 810 message = &ClientMessage{ 811 MessageId: MessageBlockBroadcast, 812 Buffer: blockData, 813 } 814 815 // Pruned block broadcast 816 prunedBuffer := make([]byte, 4, block.BufferLength()+4) 817 prunedBlockData, _ := block.AppendBinaryFlags(prunedBuffer, true, false) 818 binary.LittleEndian.PutUint32(prunedBlockData, uint32(len(prunedBlockData)-4)) 819 prunedMessage = &ClientMessage{ 820 MessageId: MessageBlockBroadcast, 821 Buffer: prunedBlockData, 822 } 823 824 // Compact block broadcast 825 compactBuffer := make([]byte, 4, block.BufferLength()+4) 826 compactBlockData, _ := block.AppendBinaryFlags(compactBuffer, true, true) 827 binary.LittleEndian.PutUint32(compactBlockData, uint32(len(compactBlockData)-4)) 828 if len(compactBlockData) >= len(prunedBlockData) { 829 //do not send compact if it ends up larger due to some reason, like parent missing or mismatch in transactions 830 compactMessage = prunedMessage 831 } else { 832 compactMessage = &ClientMessage{ 833 MessageId: MessageBlockBroadcastCompact, 834 Buffer: compactBlockData, 835 } 836 } 837 } else { 838 message = &ClientMessage{ 839 MessageId: MessageBlockBroadcast, 840 Buffer: binary.LittleEndian.AppendUint32(nil, 0), 841 } 842 prunedMessage, compactMessage = message, message 843 } 844 845 if !s.versionInformation.SupportsFeature(p2pooltypes.FeaturePrunedBroadcast) { 846 prunedMessage = message 847 } 848 849 if !s.versionInformation.SupportsFeature(p2pooltypes.FeatureCompactBroadcast) { 850 compactMessage = prunedMessage 851 } 852 853 supportsNotify := s.versionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify) 854 855 blockTemplateId := block.SideTemplateId(s.Consensus()) 856 857 go func() { 858 for _, c := range s.Clients() { 859 if c.IsGood() { 860 if !func() (sent bool) { 861 broadcastedHashes := c.BroadcastedHashes.Slice() 862 863 // has peer not broadcasted block parent to us? 864 if slices.Index(broadcastedHashes, block.Side.Parent) == -1 { 865 return false 866 } 867 // has peer not broadcasted block uncles to us? 868 for _, uncleHash := range block.Side.Uncles { 869 if slices.Index(broadcastedHashes, uncleHash) == -1 { 870 return false 871 } 872 } 873 874 // has peer broadcasted this block to us? 875 if slices.Index(broadcastedHashes, blockTemplateId) != -1 && 876 supportsNotify && c.VersionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify) { 877 c.SendBlockNotify(blockTemplateId) 878 return true 879 } 880 881 if c.VersionInformation.SupportsFeature(p2pooltypes.FeatureCompactBroadcast) { 882 c.SendMessage(compactMessage) 883 return true 884 } else if c.VersionInformation.SupportsFeature(p2pooltypes.FeaturePrunedBroadcast) { 885 c.SendMessage(prunedMessage) 886 return true 887 } 888 return false 889 }() { 890 //fallback 891 c.SendMessage(message) 892 } 893 } 894 } 895 }() 896 } 897 898 func (s *Server) HandshakeConsensusId() types.Hash { 899 return s.p2pool.Consensus().Id 900 } 901 902 func (s *Server) Consensus() *sidechain.Consensus { 903 return s.p2pool.Consensus() 904 }