github.com/amazechain/amc@v0.1.3/internal/network/service.go (about) 1 // Copyright 2022 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The AmazeChain library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package network 18 19 import ( 20 "context" 21 "crypto/rand" 22 "github.com/amazechain/amc/api/protocol/msg_proto" 23 "github.com/amazechain/amc/common" 24 "github.com/amazechain/amc/common/message" 25 "github.com/amazechain/amc/conf" 26 "github.com/amazechain/amc/log" 27 event "github.com/amazechain/amc/modules/event/v2" 28 "github.com/amazechain/amc/utils" 29 "github.com/libp2p/go-libp2p" 30 kaddht "github.com/libp2p/go-libp2p-kad-dht" 31 pubsub "github.com/libp2p/go-libp2p-pubsub" 32 "github.com/libp2p/go-libp2p/core/crypto" 33 "github.com/libp2p/go-libp2p/core/host" 34 "github.com/libp2p/go-libp2p/core/network" 35 "github.com/libp2p/go-libp2p/core/peer" 36 "github.com/libp2p/go-libp2p/p2p/security/tls" 37 "github.com/multiformats/go-multiaddr" 38 "github.com/rcrowley/go-metrics" 39 "os" 40 "os/signal" 41 "sync" 42 "syscall" 43 "time" 44 ) 45 46 const ( 47 sTopic = "newBlock" 48 ) 49 50 var ( 51 egressTrafficMeter = metrics.GetOrRegisterMeter("p2p/egress", nil) 52 ingressTrafficMeter = metrics.GetOrRegisterMeter("p2p/ingress", nil) 53 ) 54 55 type metricsLog struct{} 56 57 func (l metricsLog) Printf(format string, v ...interface{}) { 58 log.Debugf(format, v...) 59 } 60 61 type Service struct { 62 networkConfig *conf.NetWorkConfig 63 dht *kaddht.IpfsDHT 64 ctx context.Context 65 cancel context.CancelFunc 66 67 host host.Host 68 69 nodes common.PeerMap 70 boots []multiaddr.Multiaddr 71 72 lock sync.RWMutex 73 74 removeCh chan peer.ID 75 addCh chan peer.AddrInfo 76 77 bc common.IBlockChain 78 79 handlers map[message.MessageType]common.ConnHandler 80 81 joinedTopics map[string]*pubsub.Topic 82 joinedTopicsLock sync.Mutex 83 84 peerCallback common.ProtocolHandshakeFn 85 peerInfo common.ProtocolHandshakeInfo 86 87 amcPubSub common.IPubSub 88 } 89 90 func NewService(ctx context.Context, config *conf.NetWorkConfig, peers common.PeerMap, callback common.ProtocolHandshakeFn, info common.ProtocolHandshakeInfo) (common.INetwork, error) { 91 c, cancel := context.WithCancel(ctx) 92 93 s := Service{ 94 networkConfig: config, 95 ctx: c, 96 cancel: cancel, 97 nodes: peers, 98 removeCh: make(chan peer.ID, 10), 99 addCh: make(chan peer.AddrInfo, 10), 100 peerCallback: callback, 101 peerInfo: info, 102 handlers: make(map[message.MessageType]common.ConnHandler), 103 } 104 105 var peerKey crypto.PrivKey 106 var err error 107 if len(s.networkConfig.LocalPeerKey) <= 0 { 108 peerKey, _, err = crypto.GenerateEd25519Key(rand.Reader) 109 if err != nil { 110 log.Error("create peer key failed", err) 111 return nil, err 112 } 113 } else { 114 peerKey, err = utils.StringToPrivate(s.networkConfig.LocalPeerKey) 115 if err != nil { 116 log.Errorf("Failed parse string to private key %v", err) 117 return nil, err 118 } 119 } 120 121 h, err := libp2p.New(libp2p.Identity(peerKey), libp2p.ListenAddrStrings(s.networkConfig.ListenersAddress...), libp2p.Security(libp2ptls.ID, libp2ptls.New)) 122 if err != nil { 123 log.Error("create p2p host failed", "err", err) 124 return nil, err 125 } 126 127 h.SetStreamHandler(MSGProtocol, s.handleStream) 128 s.host = h 129 130 return &s, nil 131 } 132 133 func (s *Service) Bootstrapped() bool { 134 //return s.networkConfig.Bootstrapped 135 return len(s.networkConfig.BootstrapPeers) == 0 136 } 137 138 func (s *Service) Host() host.Host { 139 return s.host 140 } 141 142 func (s *Service) Start() error { 143 144 peersInfo := make([]peer.AddrInfo, 0) 145 for _, bootstrapPeer := range s.networkConfig.BootstrapPeers { 146 peerAddr, err := multiaddr.NewMultiaddr(bootstrapPeer) 147 if err != nil { 148 log.Warnf("failed parse string to muaddr %v, err %v", bootstrapPeer, err) 149 continue 150 } 151 peerInfo, err := peer.AddrInfoFromP2pAddr(peerAddr) 152 if err != nil { 153 log.Warnf("failed get peer info from muaddr %v, err %v", peerAddr.String(), err) 154 continue 155 } 156 157 if peerInfo.ID == s.host.ID() { 158 continue 159 } 160 peersInfo = append(peersInfo, *peerInfo) 161 s.boots = append(s.boots, peerAddr) 162 } 163 164 kadDHT, err := NewKadDht(s.ctx, s, s.networkConfig.Bootstrapped, peersInfo...) 165 if err != nil { 166 log.Errorf("failed to new kadDht %v", err) 167 return err 168 } 169 170 if err := kadDHT.Start(); err != nil { 171 return err 172 } 173 174 if len(peersInfo) > 0 { 175 log.Debug("start connect bootstrap peers") 176 s.connectBootsStraps(peersInfo) 177 } 178 179 hash, blockNr, _ := s.peerInfo() 180 log.Info("local peer", "PeerId", s.host.ID(), "PeerAddress", s.host.Addrs(), "BlockNr", blockNr.Uint64(), "genesisHash", hash) 181 182 go s.nodeManager(s.addCh) 183 184 return nil 185 } 186 187 func (s *Service) PeerCount() int { 188 return len(s.nodes) 189 } 190 191 // nodeManager node insert 192 func (s *Service) nodeManager(peerCh chan peer.AddrInfo) { 193 194 stateTimer := time.NewTicker(60 * time.Second) 195 defer stateTimer.Stop() 196 defer close(peerCh) 197 198 for { 199 select { 200 case <-s.ctx.Done(): 201 return 202 case p, ok := <-peerCh: 203 if ok { 204 if !s.checkNode(p.ID) { 205 log.Debug("discover new peer", "PeerID", p.ID, "PeerAddress", p.Addrs) 206 if node, err := NewNode(s.ctx, s.host, s, p, s.handlers); err == nil { 207 hash, number, err := s.peerInfo() 208 if err != nil { 209 _ = node.Close() 210 continue 211 } 212 var h msg_proto.ProtocolHandshakeMessage 213 if err := node.ProtocolHandshake(&h, AppProtocol, hash, number, true); err != nil { 214 log.Warn("cannot Handshake", "PeerID", p.ID, "PeerAddress", p.Addrs, "ProtocolID", AppProtocol, "err", err) 215 _ = node.Close() 216 } else { 217 if cPeer, ok := s.peerCallback(node, utils.ConvertH256ToHash(h.GenesisHash), utils.ConvertH256ToUint256Int(h.CurrentHeight)); ok { 218 node.Start() 219 s.addNode(cPeer) 220 log.Info("connected peer", "peerInfo", p.String(), "blockNumber", utils.ConvertH256ToUint256Int(h.CurrentHeight).Uint64()) 221 event.GlobalEvent.Send(common.PeerJoinEvent{Peer: cPeer.ID()}) 222 } else { 223 log.Error("Peer Handshake failed", "PeerID", p.ID, "PeerAddress", p.Addrs) 224 _ = node.Close() 225 } 226 } 227 } 228 } 229 } 230 case id, ok := <-s.removeCh: 231 if ok { 232 log.Infof("delete node id:%s", id.String()) 233 s.deleteNode(id) 234 event.GlobalEvent.Send(common.PeerDropEvent{Peer: id}) 235 if !s.checkBootsStrap(id.String()) { 236 s.host.Peerstore().RemovePeer(id) 237 } 238 } 239 case <-stateTimer.C: 240 s.state() 241 } 242 } 243 } 244 245 func (s *Service) checkBootsStrap(id string) bool { 246 for _, peerAddr := range s.boots { 247 peerInfo, _ := peer.AddrInfoFromP2pAddr(peerAddr) 248 if peerInfo.ID.String() == id { 249 return true 250 } 251 } 252 return false 253 } 254 255 // todo 256 func (s *Service) connectBootsStraps(bootsStraps []peer.AddrInfo) { 257 258 var wg sync.WaitGroup 259 for _, peerInfo := range bootsStraps { 260 wg.Add(1) 261 go func() { 262 defer wg.Done() 263 if err := s.host.Connect(s.ctx, peerInfo); err != nil { 264 log.Warn("Connection bootnode failed", "err", err) 265 } else { 266 log.Info("Connection established with bootnode ", "PeerID", peerInfo.ID, "PeerAddress", peerInfo.Addrs) 267 } 268 }() 269 } 270 wg.Wait() 271 } 272 273 func (s *Service) Wait() { 274 stop := make(chan os.Signal, 1) 275 signal.Notify(stop, syscall.SIGINT) 276 277 select { 278 case <-stop: 279 s.host.Close() 280 os.Exit(0) 281 } 282 } 283 284 func (s *Service) state() { 285 s.lock.Lock() 286 defer s.lock.Unlock() 287 288 for ID, p := range s.nodes { 289 log.Debug("Peer state:", "PeerID", ID, "PeerAddress", "peerCurrentNumber", p.CurrentHeight.Uint64(), p.IPeer.(*Node).Addrs(), "connectTime", common.PrettyDuration(time.Since(p.AddTimer))) 290 for protocolID, stream := range p.IPeer.(*Node).streams { 291 log.Debug(" stream state:", "protocolID", protocolID, "StreamID", stream.ID(), "connectTime", common.PrettyDuration(time.Since(stream.Stat().Opened)), "connectDirection", stream.Stat().Direction) 292 } 293 } 294 } 295 296 func (s *Service) addNode(node common.Peer) { 297 s.lock.Lock() 298 defer s.lock.Unlock() 299 if _, ok := s.nodes[node.ID()]; !ok { 300 s.nodes[node.ID()] = node 301 } 302 } 303 304 func (s *Service) deleteNode(id peer.ID) { 305 s.lock.Lock() 306 defer s.lock.Unlock() 307 if _, ok := s.nodes[id]; ok { 308 delete(s.nodes, id) 309 } 310 } 311 312 func (s *Service) checkNode(id peer.ID) bool { 313 s.lock.RLock() 314 defer s.lock.RUnlock() 315 if _, ok := s.nodes[id]; ok { 316 return ok 317 } 318 319 return false 320 } 321 322 func (s *Service) handleStream(stream network.Stream) { 323 324 if !s.checkNode(stream.Conn().RemotePeer()) { 325 log.Info("receive peer stream connect", "streamID", stream.ID(), "protocolID", stream.Protocol(), "PeerID", stream.Conn().RemotePeer()) 326 p := s.host.Peerstore().PeerInfo(stream.Conn().RemotePeer()) 327 328 if node, err := NewNode(s.ctx, s.host, s, p, s.handlers, WithStream(stream)); err != nil { 329 stream.Close() 330 log.Errorf("failed to new node %v, err %v", p.String(), err) 331 return 332 } else { 333 hash, number, err := s.peerInfo() 334 if err != nil { 335 log.Errorf("failed to get peer info, err:%v", err) 336 return 337 } 338 var h msg_proto.ProtocolHandshakeMessage 339 if err := node.AcceptHandshake(&h, AppProtocol, hash, number); err == nil { 340 if cp, ok := s.peerCallback(node, hash, number); ok { 341 node.Start() 342 s.addNode(cp) 343 } else { 344 log.Debugf("AcceptHandshake") 345 } 346 } else { 347 log.Debugf("failed accept handshake, err: %v", err) 348 } 349 350 } 351 } 352 353 log.Debugf("already add node %s", stream.Conn().ID()) 354 } 355 356 func (s *Service) HandlePeerFound(p peer.AddrInfo) { 357 select { 358 case <-s.ctx.Done(): 359 return 360 default: 361 if p.ID == s.host.ID() { 362 log.Warnf("is self peer remote=%s == self=%s", p.ID.ShortString(), s.host.ID().ShortString()) 363 return 364 } 365 s.addCh <- p 366 } 367 } 368 369 func (s *Service) SendMsgToPeer(id string, data []byte) error { 370 msg := P2PMessage{ 371 MsgType: message.MsgApplication, 372 Payload: data, 373 } 374 375 s.lock.RLock() 376 defer s.lock.RUnlock() 377 if n, ok := s.nodes[peer.ID(id)]; ok { 378 return n.Write(&msg) 379 } 380 381 return notFoundPeer 382 } 383 384 func (s *Service) ID() string { 385 if s.host != nil { 386 return s.host.ID().String() 387 } 388 return "" 389 } 390 391 func (s *Service) WriterMessage(messageType message.MessageType, payload []byte, peer peer.ID) error { 392 msg := P2PMessage{ 393 MsgType: messageType, 394 Payload: payload, 395 } 396 397 s.lock.RLock() 398 defer s.lock.RUnlock() 399 if n, ok := s.nodes[peer]; ok { 400 return n.Write(&msg) 401 } 402 403 return notFoundPeer 404 } 405 406 func (s *Service) SetHandler(mt message.MessageType, handler common.ConnHandler) error { 407 if _, ok := s.handlers[mt]; ok { 408 return nil 409 } else { 410 s.handlers[mt] = handler 411 } 412 return nil 413 } 414 415 func (s *Service) ClosePeer(id peer.ID) error { 416 return nil 417 }