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  }