github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv5/peer.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:51</date>
    10  //</624342689218826240>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package whisperv5
    29  
    30  import (
    31  	"fmt"
    32  	"time"
    33  
    34  	mapset "github.com/deckarep/golang-set"
    35  	"github.com/ethereum/go-ethereum/common"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"github.com/ethereum/go-ethereum/p2p"
    38  	"github.com/ethereum/go-ethereum/rlp"
    39  )
    40  
    41  //
    42  type Peer struct {
    43  	host    *Whisper
    44  	peer    *p2p.Peer
    45  	ws      p2p.MsgReadWriter
    46  	trusted bool
    47  
    48  known mapset.Set //
    49  
    50  	quit chan struct{}
    51  }
    52  
    53  //
    54  func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer {
    55  	return &Peer{
    56  		host:    host,
    57  		peer:    remote,
    58  		ws:      rw,
    59  		trusted: false,
    60  		known:   mapset.NewSet(),
    61  		quit:    make(chan struct{}),
    62  	}
    63  }
    64  
    65  //
    66  //
    67  func (peer *Peer) start() {
    68  	go peer.update()
    69  	log.Trace("start", "peer", peer.ID())
    70  }
    71  
    72  //
    73  func (peer *Peer) stop() {
    74  	close(peer.quit)
    75  	log.Trace("stop", "peer", peer.ID())
    76  }
    77  
    78  //
    79  //
    80  func (peer *Peer) handshake() error {
    81  //
    82  	errc := make(chan error, 1)
    83  	go func() {
    84  		errc <- p2p.Send(peer.ws, statusCode, ProtocolVersion)
    85  	}()
    86  //
    87  	packet, err := peer.ws.ReadMsg()
    88  	if err != nil {
    89  		return err
    90  	}
    91  	if packet.Code != statusCode {
    92  		return fmt.Errorf("peer [%x] sent packet %x before status packet", peer.ID(), packet.Code)
    93  	}
    94  	s := rlp.NewStream(packet.Payload, uint64(packet.Size))
    95  	peerVersion, err := s.Uint()
    96  	if err != nil {
    97  		return fmt.Errorf("peer [%x] sent bad status message: %v", peer.ID(), err)
    98  	}
    99  	if peerVersion != ProtocolVersion {
   100  		return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", peer.ID(), peerVersion, ProtocolVersion)
   101  	}
   102  //
   103  	if err := <-errc; err != nil {
   104  		return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err)
   105  	}
   106  	return nil
   107  }
   108  
   109  //
   110  //
   111  func (peer *Peer) update() {
   112  //
   113  	expire := time.NewTicker(expirationCycle)
   114  	transmit := time.NewTicker(transmissionCycle)
   115  
   116  //
   117  	for {
   118  		select {
   119  		case <-expire.C:
   120  			peer.expire()
   121  
   122  		case <-transmit.C:
   123  			if err := peer.broadcast(); err != nil {
   124  				log.Trace("broadcast failed", "reason", err, "peer", peer.ID())
   125  				return
   126  			}
   127  
   128  		case <-peer.quit:
   129  			return
   130  		}
   131  	}
   132  }
   133  
   134  //
   135  func (peer *Peer) mark(envelope *Envelope) {
   136  	peer.known.Add(envelope.Hash())
   137  }
   138  
   139  //
   140  func (peer *Peer) marked(envelope *Envelope) bool {
   141  	return peer.known.Contains(envelope.Hash())
   142  }
   143  
   144  //
   145  //
   146  func (peer *Peer) expire() {
   147  	unmark := make(map[common.Hash]struct{})
   148  	peer.known.Each(func(v interface{}) bool {
   149  		if !peer.host.isEnvelopeCached(v.(common.Hash)) {
   150  			unmark[v.(common.Hash)] = struct{}{}
   151  		}
   152  		return true
   153  	})
   154  //
   155  	for hash := range unmark {
   156  		peer.known.Remove(hash)
   157  	}
   158  }
   159  
   160  //
   161  //
   162  func (peer *Peer) broadcast() error {
   163  	var cnt int
   164  	envelopes := peer.host.Envelopes()
   165  	for _, envelope := range envelopes {
   166  		if !peer.marked(envelope) {
   167  			err := p2p.Send(peer.ws, messagesCode, envelope)
   168  			if err != nil {
   169  				return err
   170  			} else {
   171  				peer.mark(envelope)
   172  				cnt++
   173  			}
   174  		}
   175  	}
   176  	if cnt > 0 {
   177  		log.Trace("broadcast", "num. messages", cnt)
   178  	}
   179  	return nil
   180  }
   181  
   182  func (peer *Peer) ID() []byte {
   183  	id := peer.peer.ID()
   184  	return id[:]
   185  }
   186