github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/netsync/peer.go (about)

     1  package netsync
     2  
     3  import (
     4  	"encoding/hex"
     5  	"net"
     6  	"reflect"
     7  	"sync"
     8  
     9  	log "github.com/sirupsen/logrus"
    10  	"github.com/tendermint/tmlibs/flowrate"
    11  	"gopkg.in/fatih/set.v0"
    12  
    13  	"github.com/bytom/bytom/consensus"
    14  	"github.com/bytom/bytom/errors"
    15  	"github.com/bytom/bytom/protocol/bc"
    16  	"github.com/bytom/bytom/protocol/bc/types"
    17  )
    18  
    19  const (
    20  	maxKnownTxs    = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
    21  	maxKnownBlocks = 1024  // Maximum block hashes to keep in the known list (prevent DOS)
    22  )
    23  
    24  //BasePeer is the interface for connection level peer
    25  type BasePeer interface {
    26  	Addr() net.Addr
    27  	ID() string
    28  	RemoteAddrHost() string
    29  	ServiceFlag() consensus.ServiceFlag
    30  	TrafficStatus() (*flowrate.Status, *flowrate.Status)
    31  	TrySend(byte, interface{}) bool
    32  	IsLAN() bool
    33  }
    34  
    35  //BasePeerSet is the intergace for connection level peer manager
    36  type BasePeerSet interface {
    37  	StopPeerGracefully(string)
    38  	IsBanned(ip string, level byte, reason string) bool
    39  }
    40  
    41  // PeerInfo indicate peer status snap
    42  type PeerInfo struct {
    43  	ID                  string `json:"peer_id"`
    44  	RemoteAddr          string `json:"remote_addr"`
    45  	Height              uint64 `json:"height"`
    46  	Ping                string `json:"ping"`
    47  	Duration            string `json:"duration"`
    48  	TotalSent           int64  `json:"total_sent"`
    49  	TotalReceived       int64  `json:"total_received"`
    50  	AverageSentRate     int64  `json:"average_sent_rate"`
    51  	AverageReceivedRate int64  `json:"average_received_rate"`
    52  	CurrentSentRate     int64  `json:"current_sent_rate"`
    53  	CurrentReceivedRate int64  `json:"current_received_rate"`
    54  }
    55  
    56  type peer struct {
    57  	BasePeer
    58  	mtx         sync.RWMutex
    59  	services    consensus.ServiceFlag
    60  	height      uint64
    61  	hash        *bc.Hash
    62  	knownTxs    *set.Set // Set of transaction hashes known to be known by this peer
    63  	knownBlocks *set.Set // Set of block hashes known to be known by this peer
    64  	filterAdds  *set.Set // Set of addresses that the spv node cares about.
    65  }
    66  
    67  func newPeer(height uint64, hash *bc.Hash, basePeer BasePeer) *peer {
    68  	return &peer{
    69  		BasePeer:    basePeer,
    70  		services:    basePeer.ServiceFlag(),
    71  		height:      height,
    72  		hash:        hash,
    73  		knownTxs:    set.New(),
    74  		knownBlocks: set.New(),
    75  		filterAdds:  set.New(),
    76  	}
    77  }
    78  
    79  func (p *peer) Height() uint64 {
    80  	p.mtx.RLock()
    81  	defer p.mtx.RUnlock()
    82  	return p.height
    83  }
    84  
    85  func (p *peer) addFilterAddress(address []byte) {
    86  	p.mtx.Lock()
    87  	defer p.mtx.Unlock()
    88  
    89  	if p.filterAdds.Size() >= maxFilterAddressCount {
    90  		log.WithField("module", logModule).Warn("the count of filter addresses is greater than limit")
    91  		return
    92  	}
    93  	if len(address) > maxFilterAddressSize {
    94  		log.WithField("module", logModule).Warn("the size of filter address is greater than limit")
    95  		return
    96  	}
    97  
    98  	p.filterAdds.Add(hex.EncodeToString(address))
    99  }
   100  
   101  func (p *peer) addFilterAddresses(addresses [][]byte) {
   102  	if !p.filterAdds.IsEmpty() {
   103  		p.filterAdds.Clear()
   104  	}
   105  	for _, address := range addresses {
   106  		p.addFilterAddress(address)
   107  	}
   108  }
   109  
   110  func (p *peer) getBlockByHeight(height uint64) bool {
   111  	msg := struct{ BlockchainMessage }{&GetBlockMessage{Height: height}}
   112  	return p.TrySend(BlockchainChannel, msg)
   113  }
   114  
   115  func (p *peer) getBlocks(locator []*bc.Hash, stopHash *bc.Hash) bool {
   116  	msg := struct{ BlockchainMessage }{NewGetBlocksMessage(locator, stopHash)}
   117  	return p.TrySend(BlockchainChannel, msg)
   118  }
   119  
   120  func (p *peer) getHeaders(locator []*bc.Hash, stopHash *bc.Hash) bool {
   121  	msg := struct{ BlockchainMessage }{NewGetHeadersMessage(locator, stopHash)}
   122  	return p.TrySend(BlockchainChannel, msg)
   123  }
   124  
   125  func (p *peer) getPeerInfo() *PeerInfo {
   126  	p.mtx.RLock()
   127  	defer p.mtx.RUnlock()
   128  
   129  	sentStatus, receivedStatus := p.TrafficStatus()
   130  	ping := sentStatus.Idle - receivedStatus.Idle
   131  	if receivedStatus.Idle > sentStatus.Idle {
   132  		ping = -ping
   133  	}
   134  
   135  	return &PeerInfo{
   136  		ID:                  p.ID(),
   137  		RemoteAddr:          p.Addr().String(),
   138  		Height:              p.height,
   139  		Ping:                ping.String(),
   140  		Duration:            sentStatus.Duration.String(),
   141  		TotalSent:           sentStatus.Bytes,
   142  		TotalReceived:       receivedStatus.Bytes,
   143  		AverageSentRate:     sentStatus.AvgRate,
   144  		AverageReceivedRate: receivedStatus.AvgRate,
   145  		CurrentSentRate:     sentStatus.CurRate,
   146  		CurrentReceivedRate: receivedStatus.CurRate,
   147  	}
   148  }
   149  
   150  func (p *peer) getRelatedTxAndStatus(txs []*types.Tx, txStatuses *bc.TransactionStatus) ([]*types.Tx, []*bc.TxVerifyResult) {
   151  	var relatedTxs []*types.Tx
   152  	var relatedStatuses []*bc.TxVerifyResult
   153  	for i, tx := range txs {
   154  		if p.isRelatedTx(tx) {
   155  			relatedTxs = append(relatedTxs, tx)
   156  			relatedStatuses = append(relatedStatuses, txStatuses.VerifyStatus[i])
   157  		}
   158  	}
   159  	return relatedTxs, relatedStatuses
   160  }
   161  
   162  func (p *peer) isRelatedTx(tx *types.Tx) bool {
   163  	for _, input := range tx.Inputs {
   164  		switch inp := input.TypedInput.(type) {
   165  		case *types.SpendInput:
   166  			if p.filterAdds.Has(hex.EncodeToString(inp.ControlProgram)) {
   167  				return true
   168  			}
   169  		}
   170  	}
   171  	for _, output := range tx.Outputs {
   172  		if p.filterAdds.Has(hex.EncodeToString(output.ControlProgram)) {
   173  			return true
   174  		}
   175  	}
   176  	return false
   177  }
   178  
   179  func (p *peer) isSPVNode() bool {
   180  	return !p.services.IsEnable(consensus.SFFullNode)
   181  }
   182  
   183  func (p *peer) markBlock(hash *bc.Hash) {
   184  	p.mtx.Lock()
   185  	defer p.mtx.Unlock()
   186  
   187  	for p.knownBlocks.Size() >= maxKnownBlocks {
   188  		p.knownBlocks.Pop()
   189  	}
   190  	p.knownBlocks.Add(hash.String())
   191  }
   192  
   193  func (p *peer) markTransaction(hash *bc.Hash) {
   194  	p.mtx.Lock()
   195  	defer p.mtx.Unlock()
   196  
   197  	for p.knownTxs.Size() >= maxKnownTxs {
   198  		p.knownTxs.Pop()
   199  	}
   200  	p.knownTxs.Add(hash.String())
   201  }
   202  
   203  func (p *peer) sendBlock(block *types.Block) (bool, error) {
   204  	msg, err := NewBlockMessage(block)
   205  	if err != nil {
   206  		return false, errors.Wrap(err, "fail on NewBlockMessage")
   207  	}
   208  
   209  	ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
   210  	if ok {
   211  		blcokHash := block.Hash()
   212  		p.knownBlocks.Add(blcokHash.String())
   213  	}
   214  	return ok, nil
   215  }
   216  
   217  func (p *peer) sendBlocks(blocks []*types.Block) (bool, error) {
   218  	msg, err := NewBlocksMessage(blocks)
   219  	if err != nil {
   220  		return false, errors.Wrap(err, "fail on NewBlocksMessage")
   221  	}
   222  
   223  	if ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok {
   224  		return ok, nil
   225  	}
   226  
   227  	for _, block := range blocks {
   228  		blcokHash := block.Hash()
   229  		p.knownBlocks.Add(blcokHash.String())
   230  	}
   231  	return true, nil
   232  }
   233  
   234  func (p *peer) sendHeaders(headers []*types.BlockHeader) (bool, error) {
   235  	msg, err := NewHeadersMessage(headers)
   236  	if err != nil {
   237  		return false, errors.New("fail on NewHeadersMessage")
   238  	}
   239  
   240  	ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
   241  	return ok, nil
   242  }
   243  
   244  func (p *peer) sendMerkleBlock(block *types.Block, txStatuses *bc.TransactionStatus) (bool, error) {
   245  	msg := NewMerkleBlockMessage()
   246  	if err := msg.setRawBlockHeader(block.BlockHeader); err != nil {
   247  		return false, err
   248  	}
   249  
   250  	relatedTxs, relatedStatuses := p.getRelatedTxAndStatus(block.Transactions, txStatuses)
   251  
   252  	txHashes, txFlags := types.GetTxMerkleTreeProof(block.Transactions, relatedTxs)
   253  	if err := msg.setTxInfo(txHashes, txFlags, relatedTxs); err != nil {
   254  		return false, nil
   255  	}
   256  
   257  	statusHashes := types.GetStatusMerkleTreeProof(txStatuses.VerifyStatus, txFlags)
   258  	if err := msg.setStatusInfo(statusHashes, relatedStatuses); err != nil {
   259  		return false, nil
   260  	}
   261  
   262  	ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
   263  	return ok, nil
   264  }
   265  
   266  func (p *peer) sendTransactions(txs []*types.Tx) (bool, error) {
   267  	for _, tx := range txs {
   268  		if p.isSPVNode() && !p.isRelatedTx(tx) {
   269  			continue
   270  		}
   271  		msg, err := NewTransactionMessage(tx)
   272  		if err != nil {
   273  			return false, errors.Wrap(err, "failed to tx msg")
   274  		}
   275  
   276  		if p.knownTxs.Has(tx.ID.String()) {
   277  			continue
   278  		}
   279  		if ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok {
   280  			return ok, nil
   281  		}
   282  		p.knownTxs.Add(tx.ID.String())
   283  	}
   284  	return true, nil
   285  }
   286  
   287  func (p *peer) setStatus(height uint64, hash *bc.Hash) {
   288  	p.mtx.Lock()
   289  	defer p.mtx.Unlock()
   290  	p.height = height
   291  	p.hash = hash
   292  }
   293  
   294  type peerSet struct {
   295  	BasePeerSet
   296  	mtx   sync.RWMutex
   297  	peers map[string]*peer
   298  }
   299  
   300  // newPeerSet creates a new peer set to track the active participants.
   301  func newPeerSet(basePeerSet BasePeerSet) *peerSet {
   302  	return &peerSet{
   303  		BasePeerSet: basePeerSet,
   304  		peers:       make(map[string]*peer),
   305  	}
   306  }
   307  
   308  func (ps *peerSet) ProcessIllegal(peerID string, level byte, reason string) {
   309  	ps.mtx.Lock()
   310  	peer := ps.peers[peerID]
   311  	ps.mtx.Unlock()
   312  
   313  	if peer == nil {
   314  		return
   315  	}
   316  	if banned := ps.IsBanned(peer.RemoteAddrHost(), level, reason); banned {
   317  		ps.removePeer(peerID)
   318  	}
   319  	return
   320  }
   321  
   322  func (ps *peerSet) addPeer(peer BasePeer, height uint64, hash *bc.Hash) {
   323  	ps.mtx.Lock()
   324  	defer ps.mtx.Unlock()
   325  
   326  	if _, ok := ps.peers[peer.ID()]; !ok {
   327  		ps.peers[peer.ID()] = newPeer(height, hash, peer)
   328  		return
   329  	}
   330  	log.WithField("module", logModule).Warning("add existing peer to blockKeeper")
   331  }
   332  
   333  func (ps *peerSet) bestPeer(flag consensus.ServiceFlag) *peer {
   334  	ps.mtx.RLock()
   335  	defer ps.mtx.RUnlock()
   336  
   337  	var bestPeer *peer
   338  	for _, p := range ps.peers {
   339  		if !p.services.IsEnable(flag) {
   340  			continue
   341  		}
   342  		if bestPeer == nil || p.height > bestPeer.height || (p.height == bestPeer.height && p.IsLAN()) {
   343  			bestPeer = p
   344  		}
   345  	}
   346  	return bestPeer
   347  }
   348  
   349  func (ps *peerSet) broadcastMinedBlock(block *types.Block) error {
   350  	msg, err := NewMinedBlockMessage(block)
   351  	if err != nil {
   352  		return errors.Wrap(err, "fail on broadcast mined block")
   353  	}
   354  
   355  	hash := block.Hash()
   356  	peers := ps.peersWithoutBlock(&hash)
   357  	for _, peer := range peers {
   358  		if peer.isSPVNode() {
   359  			continue
   360  		}
   361  		if ok := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok {
   362  			log.WithFields(log.Fields{"module": logModule, "peer": peer.Addr(), "type": reflect.TypeOf(msg), "message": msg.String()}).Warning("send message to peer error")
   363  			ps.removePeer(peer.ID())
   364  			continue
   365  		}
   366  		peer.markBlock(&hash)
   367  	}
   368  	return nil
   369  }
   370  
   371  func (ps *peerSet) broadcastNewStatus(bestBlock, genesisBlock *types.Block) error {
   372  	bestBlockHash := bestBlock.Hash()
   373  	peers := ps.peersWithoutBlock(&bestBlockHash)
   374  
   375  	genesisHash := genesisBlock.Hash()
   376  	msg := NewStatusResponseMessage(&bestBlock.BlockHeader, &genesisHash)
   377  	for _, peer := range peers {
   378  		if ok := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok {
   379  			log.WithFields(log.Fields{"module": logModule, "peer": peer.Addr(), "type": reflect.TypeOf(msg), "message": msg.String()}).Warning("send message to peer error")
   380  			ps.removePeer(peer.ID())
   381  			continue
   382  		}
   383  	}
   384  	return nil
   385  }
   386  
   387  func (ps *peerSet) broadcastTx(tx *types.Tx) error {
   388  	msg, err := NewTransactionMessage(tx)
   389  	if err != nil {
   390  		return errors.Wrap(err, "fail on broadcast tx")
   391  	}
   392  
   393  	peers := ps.peersWithoutTx(&tx.ID)
   394  	for _, peer := range peers {
   395  		if peer.isSPVNode() && !peer.isRelatedTx(tx) {
   396  			continue
   397  		}
   398  		if ok := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok {
   399  			log.WithFields(log.Fields{
   400  				"module":  logModule,
   401  				"peer":    peer.Addr(),
   402  				"type":    reflect.TypeOf(msg),
   403  				"message": msg.String(),
   404  			}).Warning("send message to peer error")
   405  			ps.removePeer(peer.ID())
   406  			continue
   407  		}
   408  		peer.markTransaction(&tx.ID)
   409  	}
   410  	return nil
   411  }
   412  
   413  // Peer retrieves the registered peer with the given id.
   414  func (ps *peerSet) getPeer(id string) *peer {
   415  	ps.mtx.RLock()
   416  	defer ps.mtx.RUnlock()
   417  	return ps.peers[id]
   418  }
   419  
   420  func (ps *peerSet) getPeerInfos() []*PeerInfo {
   421  	ps.mtx.RLock()
   422  	defer ps.mtx.RUnlock()
   423  
   424  	result := []*PeerInfo{}
   425  	for _, peer := range ps.peers {
   426  		result = append(result, peer.getPeerInfo())
   427  	}
   428  	return result
   429  }
   430  
   431  func (ps *peerSet) peersWithoutBlock(hash *bc.Hash) []*peer {
   432  	ps.mtx.RLock()
   433  	defer ps.mtx.RUnlock()
   434  
   435  	peers := []*peer{}
   436  	for _, peer := range ps.peers {
   437  		if !peer.knownBlocks.Has(hash.String()) {
   438  			peers = append(peers, peer)
   439  		}
   440  	}
   441  	return peers
   442  }
   443  
   444  func (ps *peerSet) peersWithoutTx(hash *bc.Hash) []*peer {
   445  	ps.mtx.RLock()
   446  	defer ps.mtx.RUnlock()
   447  
   448  	peers := []*peer{}
   449  	for _, peer := range ps.peers {
   450  		if !peer.knownTxs.Has(hash.String()) {
   451  			peers = append(peers, peer)
   452  		}
   453  	}
   454  	return peers
   455  }
   456  
   457  func (ps *peerSet) removePeer(peerID string) {
   458  	ps.mtx.Lock()
   459  	delete(ps.peers, peerID)
   460  	ps.mtx.Unlock()
   461  	ps.StopPeerGracefully(peerID)
   462  }