github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/dpos/routes.go (about)

     1  // Copyright (c) 2017-2019 The Elastos Foundation
     2  // Use of this source code is governed by an MIT
     3  // license that can be found in the LICENSE file.
     4  //
     5  
     6  package dpos
     7  
     8  import (
     9  	"bytes"
    10  	"container/list"
    11  	"fmt"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"github.com/elastos/Elastos.ELA/common"
    17  	"github.com/elastos/Elastos.ELA/crypto"
    18  	"github.com/elastos/Elastos.ELA/dpos/dtime"
    19  	"github.com/elastos/Elastos.ELA/dpos/p2p/peer"
    20  	"github.com/elastos/Elastos.ELA/events"
    21  	"github.com/elastos/Elastos.ELA/p2p/msg"
    22  )
    23  
    24  type IPeer interface {
    25  	Disconnect()
    26  	SendELAMessage(msg *ElaMsg)
    27  }
    28  
    29  const (
    30  	// minPeersToAnnounce defines the minimum connected peers to announce
    31  	// DPOS address into the P2P network.
    32  	minPeersToAnnounce = 5
    33  
    34  	// retryAnnounceDuration defines the time duration to retry an announce.
    35  	retryAnnounceDuration = 3 * time.Second
    36  
    37  	// maxTimeOffset indicates the maximum time offset with the to accept an
    38  	// DAddr message.
    39  	maxTimeOffset = 30 * time.Second
    40  
    41  	// minAnnounceDuration indicates the minimum allowed time duration to
    42  	// announce a new DAddr.
    43  	minAnnounceDuration = 30 * time.Second
    44  
    45  	// maxKnownAddrs indicates the maximum known DAddrs cached in memory.
    46  	// The maximum of DAddrs can be calculated as [36(current)+72(candidate)]².
    47  	maxKnownAddrs = 108 * 110
    48  )
    49  
    50  // Config defines the parameters to create a Route instance.
    51  type Config struct {
    52  	// The PID of this peer if it is an producer.
    53  	PID []byte
    54  
    55  	// The network address of this arbiter.
    56  	Addr string
    57  
    58  	// TimeSource is the median time source of the P2P network.
    59  	TimeSource dtime.MedianTimeSource
    60  
    61  	// Sign the addr message of this arbiter.
    62  	Sign func(data []byte) (signature []byte)
    63  
    64  	// IsCurrent returns whether BlockChain synced to best height.
    65  	IsCurrent func() bool
    66  
    67  	// RelayAddr relays the addresses inventory to the P2P network.
    68  	RelayAddr func(iv *msg.InvVect, data interface{})
    69  
    70  	// OnCipherAddr will be invoked when an address cipher received.
    71  	OnCipherAddr func(pid peer.PID, cipher []byte)
    72  }
    73  
    74  // cache stores the requested DAddrs from a peer.
    75  type cache struct {
    76  	requested map[common.Uint256]struct{}
    77  }
    78  
    79  // state stores the DPOS addresses and other additional information tracking
    80  // addresses syncing status.
    81  type state struct {
    82  	peers     map[peer.PID]struct{}
    83  	requested map[common.Uint256]struct{}
    84  	peerCache map[IPeer]*cache
    85  }
    86  
    87  type newPeerMsg IPeer
    88  
    89  type peersMsg struct {
    90  	peers []peer.PID
    91  }
    92  
    93  type invMsg struct {
    94  	peer IPeer
    95  	msg  *msg.Inv
    96  }
    97  
    98  type dAddrMsg struct {
    99  	peer IPeer
   100  	msg  *msg.DAddr
   101  }
   102  
   103  type Routes struct {
   104  	selfPID peer.PID
   105  	cfg     *Config
   106  	addr    string
   107  	sign    func([]byte) []byte
   108  
   109  	// The following variables must only be used atomically.
   110  	started int32
   111  	stopped int32
   112  	waiting int32
   113  
   114  	addrMtx   sync.RWMutex
   115  	addrIndex map[peer.PID]map[peer.PID]common.Uint256
   116  	knownAddr map[common.Uint256]*msg.DAddr
   117  	knownList *list.List
   118  
   119  	queue     chan interface{}
   120  	donequeue chan IPeer
   121  	announce  chan struct{}
   122  	quit      chan struct{}
   123  }
   124  
   125  // New creates and return a Routes instance.
   126  func New(cfg *Config) *Routes {
   127  	var pid peer.PID
   128  	copy(pid[:], cfg.PID)
   129  
   130  	r := Routes{
   131  		selfPID:   pid,
   132  		cfg:       cfg,
   133  		addr:      cfg.Addr,
   134  		sign:      cfg.Sign,
   135  		addrIndex: make(map[peer.PID]map[peer.PID]common.Uint256),
   136  		knownAddr: make(map[common.Uint256]*msg.DAddr),
   137  		knownList: list.New(),
   138  		queue:     make(chan interface{}, 125),
   139  		donequeue: make(chan IPeer, 1),
   140  		announce:  make(chan struct{}, 1),
   141  		quit:      make(chan struct{}),
   142  	}
   143  
   144  	events.Subscribe(func(e *events.Event) {
   145  		switch e.Type {
   146  		case events.ETDirectPeersChanged:
   147  			peersInfo := e.Data.(*peer.PeersInfo)
   148  			current := peersInfo.CurrentPeers
   149  			next := peersInfo.NextPeers
   150  			if next != nil {
   151  				current = append(current, next...)
   152  			}
   153  			go r.PeersChanged(current)
   154  		case ETElaMsg:
   155  			go r.ElaMsg(e.Data.(*MsgEvent))
   156  		case ETNewPeer:
   157  			go r.NewPeer(e.Data.(IPeer))
   158  		case ETDonePeer:
   159  			go r.DonePeer(e.Data.(IPeer))
   160  		case ETStopRoutes:
   161  			go r.Stop()
   162  		case ETAnnounceAddr:
   163  			go r.AnnounceAddr()
   164  		}
   165  	})
   166  	return &r
   167  }
   168  
   169  func (r *Routes) PeersChanged(peers []peer.PID) {
   170  	r.queue <- peersMsg{peers: peers}
   171  }
   172  
   173  // NewPeer notifies the new connected peer.
   174  func (r *Routes) NewPeer(peer IPeer) {
   175  	r.queue <- newPeerMsg(peer)
   176  }
   177  
   178  // DonePeer notifies the disconnected peer.
   179  func (r *Routes) DonePeer(peer IPeer) {
   180  	r.donequeue <- peer
   181  }
   182  
   183  func (r *Routes) ElaMsg(msgEvent *MsgEvent) {
   184  	switch msgEvent.ElaMsg.Type {
   185  	case Inv:
   186  		var inv msg.Inv
   187  		if err := inv.Deserialize(bytes.NewReader(msgEvent.ElaMsg.Msg)); err != nil {
   188  			Error("ElaMsg error,", err)
   189  		}
   190  		r.queue <- invMsg{peer: msgEvent.Peer, msg: &inv}
   191  	case GetData:
   192  		var getData msg.GetData
   193  		if err := getData.Deserialize(bytes.NewReader(msgEvent.ElaMsg.Msg)); err != nil {
   194  			Error("ElaMsg error,", err)
   195  		}
   196  		r.OnGetData(msgEvent.Peer, &getData)
   197  	case DAddr:
   198  		var dAddr msg.DAddr
   199  		if err := dAddr.Deserialize(bytes.NewReader(msgEvent.ElaMsg.Msg)); err != nil {
   200  			Error("ElaMsg error,", err)
   201  		}
   202  		r.queue <- dAddrMsg{peer: msgEvent.Peer, msg: &dAddr}
   203  	default:
   204  		Warn("Invalid ElaMsg type")
   205  	}
   206  }
   207  
   208  // Start starts the Routes instance to sync DPOS addresses.
   209  func (r *Routes) Start() {
   210  	if !atomic.CompareAndSwapInt32(&r.started, 0, 1) {
   211  		return
   212  	}
   213  	go r.addrHandler()
   214  }
   215  
   216  // Stop quits the syncing address handler.
   217  func (r *Routes) Stop() {
   218  	if !atomic.CompareAndSwapInt32(&r.stopped, 0, 1) {
   219  		return
   220  	}
   221  	close(r.quit)
   222  }
   223  
   224  // addrHandler is the main handler to syncing the addresses state.
   225  func (r *Routes) addrHandler() {
   226  	state := &state{
   227  		peers:     make(map[peer.PID]struct{}),
   228  		requested: make(map[common.Uint256]struct{}),
   229  		peerCache: make(map[IPeer]*cache),
   230  	}
   231  
   232  	// lastAnnounce indicates the time when last announce sent.
   233  	var lastAnnounce time.Time
   234  
   235  	// scheduleAnnounce schedules an announce according to the delay time.
   236  	var scheduleAnnounce = func(delay time.Duration) {
   237  		time.AfterFunc(delay, func() {
   238  			r.announce <- struct{}{}
   239  		})
   240  	}
   241  
   242  out:
   243  	for {
   244  		select {
   245  		// Handle the messages from queue.
   246  		case m := <-r.queue:
   247  			switch m := m.(type) {
   248  			case newPeerMsg:
   249  				r.handleNewPeer(state, m)
   250  
   251  			case invMsg:
   252  				r.handleInv(state, m.peer, m.msg)
   253  
   254  			case dAddrMsg:
   255  				r.handleDAddr(state, m.peer, m.msg)
   256  
   257  			case peersMsg:
   258  				r.handlePeersMsg(state, m.peers)
   259  			}
   260  
   261  		// Handle the announce request.
   262  		case <-r.announce:
   263  			// This may be a retry or delayed announce, and the DPoS producers
   264  			// have been changed.
   265  			_, ok := state.peers[r.selfPID]
   266  			if !ok {
   267  				// Waiting status must reset here or the announce will never
   268  				// work again.
   269  				atomic.StoreInt32(&r.waiting, 0)
   270  				//continue
   271  			}
   272  
   273  			//TODO Temporary cancellation
   274  			// Do not announce address if connected peers not enough.
   275  			if len(state.peerCache) < minPeersToAnnounce {
   276  				// Retry announce after the retry duration.
   277  				//scheduleAnnounce(retryAnnounceDuration)
   278  				//continue
   279  			}
   280  
   281  			// Do not announce address too frequent.
   282  			now := time.Now()
   283  			if lastAnnounce.Add(minAnnounceDuration).After(now) {
   284  				// Calculate next announce time and schedule an announce.
   285  				nextAnnounce := minAnnounceDuration - now.Sub(lastAnnounce)
   286  				scheduleAnnounce(nextAnnounce)
   287  				continue
   288  			}
   289  
   290  			// Update last announce time.
   291  			lastAnnounce = now
   292  			// Reset waiting state to 0(false).
   293  			atomic.StoreInt32(&r.waiting, 0)
   294  
   295  			for pid := range state.peers {
   296  				// Do not create address for self.
   297  				if r.selfPID.Equal(pid) {
   298  					continue
   299  				}
   300  
   301  				pubKey, err := crypto.DecodePoint(pid[:])
   302  				if err != nil {
   303  					continue
   304  				}
   305  
   306  				// Generate DAddr for the given PID.
   307  				cipher, err := crypto.Encrypt(pubKey, []byte(r.addr))
   308  				if err != nil {
   309  					Warnf("encrypt addr %s failed %s", r.addr, err)
   310  					continue
   311  				}
   312  				addr := msg.DAddr{
   313  					PID:       r.selfPID,
   314  					Timestamp: time.Now(),
   315  					Encode:    pid,
   316  					Cipher:    cipher,
   317  				}
   318  				addr.Signature = r.sign(addr.Data())
   319  
   320  				// Append and relay the local address.
   321  				r.appendAddr(&addr)
   322  			}
   323  		case m := <-r.donequeue:
   324  			r.handleDonePeer(state, m)
   325  
   326  		case <-r.quit:
   327  			break out
   328  		}
   329  	}
   330  
   331  cleanup:
   332  	for {
   333  		select {
   334  		case <-r.queue:
   335  		case <-r.announce:
   336  		default:
   337  			break cleanup
   338  		}
   339  	}
   340  }
   341  
   342  func (r *Routes) handlePeersMsg(state *state, peers []peer.PID) {
   343  	// Compare current peers and new peers to find the difference.
   344  	var newPeers = make(map[peer.PID]struct{})
   345  	for _, pid := range peers {
   346  		newPeers[pid] = struct{}{}
   347  
   348  		// Initiate address index.
   349  		r.addrMtx.RLock()
   350  		_, ok := r.addrIndex[pid]
   351  		r.addrMtx.RUnlock()
   352  		if !ok {
   353  			r.addrMtx.Lock()
   354  			r.addrIndex[pid] = make(map[peer.PID]common.Uint256)
   355  			r.addrMtx.Unlock()
   356  		}
   357  	}
   358  
   359  	// Remove peers that not in new peers list.
   360  	var delPeers []peer.PID
   361  	for pid := range state.peers {
   362  		if _, ok := newPeers[pid]; ok {
   363  			continue
   364  		}
   365  		delPeers = append(delPeers, pid)
   366  	}
   367  
   368  	for _, pid := range delPeers {
   369  		// Remove from index and known addr.
   370  		r.addrMtx.RLock()
   371  		pids, ok := r.addrIndex[pid]
   372  		r.addrMtx.RUnlock()
   373  		if !ok {
   374  			continue
   375  		}
   376  
   377  		r.addrMtx.Lock()
   378  		for _, pid := range pids {
   379  			delete(r.knownAddr, pid)
   380  		}
   381  		delete(r.addrIndex, pid)
   382  		r.addrMtx.Unlock()
   383  	}
   384  
   385  	// Update peers list.
   386  	_, isProducer := newPeers[r.selfPID]
   387  	_, wasProducer := state.peers[r.selfPID]
   388  	state.peers = newPeers
   389  
   390  	// Announce address into P2P network if we become arbiter.
   391  	if isProducer && !wasProducer {
   392  		r.announceAddr()
   393  	}
   394  }
   395  
   396  // AnnounceAddr schedules an local address announce to the P2P network, it used
   397  // to re-announce the local address when DPoS network go bad.
   398  func (r *Routes) AnnounceAddr() {
   399  	if atomic.LoadInt32(&r.started) == 0 {
   400  		return
   401  	}
   402  	r.announceAddr()
   403  }
   404  
   405  func (r *Routes) announceAddr() {
   406  	// Ignore if BlockChain not sync to current.
   407  	if !r.cfg.IsCurrent() {
   408  		Warn("announce Addr error, blockChain not sync to current")
   409  		return
   410  	}
   411  
   412  	//Refuse new announce if a previous announce is waiting,
   413  	//this is to reduce unnecessary announce.
   414  	if !atomic.CompareAndSwapInt32(&r.waiting, 0, 1) {
   415  		return
   416  	}
   417  	r.announce <- struct{}{}
   418  }
   419  
   420  func (r *Routes) handleDAddr(s *state, p IPeer, m *msg.DAddr) {
   421  	c, exists := s.peerCache[p]
   422  	if !exists {
   423  		Warnf("Received getdaddr message for unknown peer %s", p)
   424  		return
   425  	}
   426  
   427  	hash := m.Hash()
   428  
   429  	if _, ok := c.requested[hash]; !ok {
   430  		Warnf("Got unrequested addr %s from %s -- disconnecting",
   431  			hash, p)
   432  		p.Disconnect()
   433  		return
   434  	}
   435  
   436  	delete(c.requested, hash)
   437  	delete(s.requested, hash)
   438  
   439  	if err := r.verifyDAddr(s, m); err != nil {
   440  		Warnf("Got invalid addr %s %s from %s -- disconnecting",
   441  			hash, err, p)
   442  		p.Disconnect()
   443  		return
   444  	}
   445  
   446  	_, ok := s.peers[m.PID]
   447  	if !ok {
   448  		Debugf("PID not in arbiter list")
   449  
   450  		// Peers may have disagree with the current producers, so some times we
   451  		// receive addresses that not in the producers list.  We do not
   452  		// disconnect the peer even the address not in producers list.
   453  		return
   454  	}
   455  
   456  	// Append received addr into state.
   457  	r.appendAddr(m)
   458  
   459  	// Notify the received DPOS address if the Encode matches.
   460  	if r.selfPID.Equal(m.Encode) && r.cfg.OnCipherAddr != nil {
   461  		r.cfg.OnCipherAddr(m.PID, m.Cipher)
   462  	}
   463  }
   464  
   465  func (r *Routes) appendAddr(m *msg.DAddr) {
   466  	hash := m.Hash()
   467  
   468  	// Append received addr into known addr index.
   469  	r.addrMtx.Lock()
   470  	//r.addrIndex[m.PID][m.Encode] = hash
   471  	r.knownAddr[hash] = m
   472  	if len(r.knownAddr) > maxKnownAddrs {
   473  		node := r.knownList.Back()
   474  		lru := node.Value.(common.Uint256)
   475  
   476  		delete(r.knownAddr, lru)
   477  
   478  		node.Value = hash
   479  		r.knownList.MoveToFront(node)
   480  	} else {
   481  		r.knownList.PushFront(hash)
   482  	}
   483  	r.addrMtx.Unlock()
   484  
   485  	// Relay addr to the P2P network.
   486  	iv := msg.NewInvVect(msg.InvTypeAddress, &hash)
   487  	r.cfg.RelayAddr(iv, m)
   488  }
   489  
   490  func (r *Routes) handleNewPeer(s *state, p IPeer) {
   491  	// Create state for the new peer.
   492  	s.peerCache[p] = &cache{requested: make(map[common.Uint256]struct{})}
   493  }
   494  
   495  func (r *Routes) handleDonePeer(s *state, p IPeer) {
   496  	c, exists := s.peerCache[p]
   497  	if !exists {
   498  		Warnf("Received done peer message for unknown peer %s", p)
   499  		return
   500  	}
   501  
   502  	// Remove done peer from peer state.
   503  	delete(s.peerCache, p)
   504  
   505  	// Clear cached information.
   506  	for pid := range c.requested {
   507  		delete(c.requested, pid)
   508  	}
   509  }
   510  
   511  func (r *Routes) handleInv(s *state, p IPeer, m *msg.Inv) {
   512  	c, exists := s.peerCache[p]
   513  	if !exists {
   514  		Warnf("Received inv message for unknown peer %s", p)
   515  		return
   516  	}
   517  
   518  	// Push GetData message according to the Inv message.
   519  	getData := msg.NewGetData()
   520  	for _, iv := range m.InvList {
   521  		switch iv.Type {
   522  		case msg.InvTypeAddress:
   523  		default:
   524  			continue
   525  		}
   526  
   527  		// Add the inventory to the cache of known inventory
   528  		// for the peer.
   529  		//p.AddKnownInventory(iv)
   530  
   531  		r.addrMtx.RLock()
   532  		_, ok := r.knownAddr[iv.Hash]
   533  		r.addrMtx.RUnlock()
   534  		if ok {
   535  			continue
   536  		}
   537  
   538  		if _, ok := s.requested[iv.Hash]; ok {
   539  			continue
   540  		}
   541  
   542  		c.requested[iv.Hash] = struct{}{}
   543  		s.requested[iv.Hash] = struct{}{}
   544  		getData.AddInvVect(msg.NewInvVect(msg.InvTypeAddress, &iv.Hash))
   545  	}
   546  
   547  	if len(getData.InvList) > 0 {
   548  		getDataBuf := new(bytes.Buffer)
   549  		getData.Serialize(getDataBuf)
   550  		p.SendELAMessage(&ElaMsg{
   551  			Type: GetData,
   552  			Msg:  getDataBuf.Bytes(),
   553  		})
   554  	}
   555  }
   556  
   557  // verifyDAddr verifies if this is a valid DPOS address message.
   558  func (r *Routes) verifyDAddr(s *state, m *msg.DAddr) error {
   559  	// Verify signature of the message.
   560  	pubKey, err := crypto.DecodePoint(m.PID[:])
   561  	if err != nil {
   562  		return fmt.Errorf("invalid public key")
   563  	}
   564  	err = crypto.Verify(*pubKey, m.Data(), m.Signature)
   565  	if err != nil {
   566  		return fmt.Errorf("invalid signature")
   567  	}
   568  
   569  	// Verify timestamp of the message. A DAddr to same arbiter can not be sent
   570  	// frequently to prevent attack, and a DAddr timestamp must not to far from
   571  	// the P2P network median time.
   572  	r.addrMtx.RLock()
   573  	defer r.addrMtx.RUnlock()
   574  	if index, ok := r.addrIndex[m.PID]; ok {
   575  		if hash, ok := index[m.Encode]; ok {
   576  			ka, ok := r.knownAddr[hash]
   577  			if !ok {
   578  				// This may happen if the known DAddr has been deleted because
   579  				// maxKnownAddrs arrived.  In this case we do not return any
   580  				// error.
   581  				Debugf("unknown addr %s", hash)
   582  				return nil
   583  			}
   584  
   585  			// Abandon address older than the known address to the same arbiter.
   586  			if ka.Timestamp.After(m.Timestamp) {
   587  				return fmt.Errorf("timestamp is older than known")
   588  			}
   589  
   590  			//TODO add adjustedtime
   591  			//// Check if timestamp out of median time offset.
   592  			medianTime := r.cfg.TimeSource.AdjustedTime()
   593  			minTime := medianTime.Add(-maxTimeOffset)
   594  			maxTime := medianTime.Add(maxTimeOffset)
   595  			if m.Timestamp.Before(minTime) || m.Timestamp.After(maxTime) {
   596  				return fmt.Errorf("timestamp out of offset range")
   597  			}
   598  
   599  			// Check if the address announces too frequent.
   600  			if ka.Timestamp.Add(minAnnounceDuration).After(m.Timestamp) {
   601  				return fmt.Errorf("address announce too frequent")
   602  			}
   603  		}
   604  	}
   605  
   606  	return nil
   607  }
   608  
   609  // OnGetData handles the passed GetData message of the peer.
   610  func (r *Routes) OnGetData(p IPeer, m *msg.GetData) {
   611  	for _, iv := range m.InvList {
   612  		switch iv.Type {
   613  		case msg.InvTypeAddress:
   614  			// Attempt to fetch the requested addr.
   615  			r.addrMtx.RLock()
   616  			addr, ok := r.knownAddr[iv.Hash]
   617  			r.addrMtx.RUnlock()
   618  			if !ok {
   619  				Warnf("%s for DAddr not found", iv.Hash)
   620  				continue
   621  			}
   622  			addrBuf := new(bytes.Buffer)
   623  			addr.Serialize(addrBuf)
   624  			p.SendELAMessage(&ElaMsg{
   625  				Type: DAddr,
   626  				Msg:  addrBuf.Bytes(),
   627  			})
   628  
   629  		default:
   630  			continue
   631  		}
   632  	}
   633  }
   634  
   635  // QueueInv adds the passed Inv message and peer to the addr handling queue.
   636  func (r *Routes) QueueInv(p IPeer, m *msg.Inv) {
   637  	// Filter non-address inventory messages.
   638  	for _, iv := range m.InvList {
   639  		if iv.Type == msg.InvTypeAddress {
   640  			r.queue <- invMsg{peer: p, msg: m}
   641  			return
   642  		}
   643  	}
   644  }