github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/discovery/dhtdiscovery/node.go (about) 1 /* 2 * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU 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 * This program 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 General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package dhtdiscovery 19 20 import ( 21 "context" 22 "fmt" 23 24 "github.com/libp2p/go-libp2p" 25 "github.com/libp2p/go-libp2p/core/host" 26 "github.com/libp2p/go-libp2p/core/peer" 27 "github.com/multiformats/go-multiaddr" 28 "github.com/rs/zerolog/log" 29 ) 30 31 // Node represents DHT server-client in P2P network. 32 type Node struct { 33 libP2PConfig libp2p.Config 34 libP2PNode host.Host 35 libP2PNodeCtx context.Context 36 libP2PNodeCancel context.CancelFunc 37 38 bootstrapPeers []*peer.AddrInfo 39 } 40 41 // NewNode create an instance of DHT node. 42 func NewNode(listenAddress string, bootstrapPeerAddresses []string) (*Node, error) { 43 node := &Node{ 44 bootstrapPeers: make([]*peer.AddrInfo, len(bootstrapPeerAddresses)), 45 } 46 47 // Parse and validate configuration 48 listenAddr, err := multiaddr.NewMultiaddr(listenAddress) 49 if err != nil { 50 return nil, fmt.Errorf("failed to parse DHT listen address: %w", err) 51 } 52 53 for i, peerAddress := range bootstrapPeerAddresses { 54 peerAddr, err := multiaddr.NewMultiaddr(peerAddress) 55 if err != nil { 56 return nil, fmt.Errorf("failed to parse DHT peer address: %w", err) 57 } 58 59 if node.bootstrapPeers[i], err = peer.AddrInfoFromP2pAddr(peerAddr); err != nil { 60 return nil, fmt.Errorf("failed to parse DHT peer info: %w", err) 61 } 62 } 63 64 // Preparing config for libp2p Host. Other options can be added here. 65 if err = node.libP2PConfig.Apply( 66 libp2p.ListenAddrs(listenAddr), 67 libp2p.FallbackDefaults, 68 ); err != nil { 69 return nil, fmt.Errorf("failed to configure DHT node: %w", err) 70 } 71 72 return node, nil 73 } 74 75 // Start begins DHT bootstrapping process. 76 func (n *Node) Start() (err error) { 77 // Prepare context which stops the libp2p host. 78 n.libP2PNodeCtx, n.libP2PNodeCancel = context.WithCancel(context.Background()) 79 80 // Start libp2p node. 81 n.libP2PNode, err = n.libP2PConfig.NewNode() 82 if err != nil { 83 return fmt.Errorf("failed to start DHT node: %w", err) 84 } 85 86 log.Info().Msgf("DHT node started on %s with ID=%s", n.libP2PNode.Addrs(), n.libP2PNode.ID()) 87 88 // Start connecting to the bootstrap peer nodes early. They will tell us about the other nodes in the network. 89 for _, peerInfo := range n.bootstrapPeers { 90 go n.connectToPeer(*peerInfo) 91 } 92 93 return nil 94 } 95 96 // Stop stops DHT node. 97 func (n *Node) Stop() { 98 n.libP2PNodeCancel() 99 n.libP2PNode.Close() 100 } 101 102 func (n *Node) connectToPeer(peerInfo peer.AddrInfo) { 103 if err := n.libP2PNode.Connect(n.libP2PNodeCtx, peerInfo); err != nil { 104 log.Warn().Err(err).Msgf("Failed to contact DHT peer %s", peerInfo.ID) 105 106 return 107 } 108 109 log.Info().Msgf("Connection established with DHT peer: %v", peerInfo) 110 }