github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/whisper/whisperv5/peer.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package whisperv5 18 19 import ( 20 "fmt" 21 "time" 22 23 "github.com/atheioschain/go-atheios/common" 24 "github.com/atheioschain/go-atheios/logger" 25 "github.com/atheioschain/go-atheios/logger/glog" 26 "github.com/atheioschain/go-atheios/p2p" 27 "github.com/atheioschain/go-atheios/rlp" 28 set "gopkg.in/fatih/set.v0" 29 ) 30 31 // peer represents a whisper protocol peer connection. 32 type Peer struct { 33 host *Whisper 34 peer *p2p.Peer 35 ws p2p.MsgReadWriter 36 trusted bool 37 38 known *set.Set // Messages already known by the peer to avoid wasting bandwidth 39 40 quit chan struct{} 41 } 42 43 // newPeer creates a new whisper peer object, but does not run the handshake itself. 44 func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer { 45 return &Peer{ 46 host: host, 47 peer: remote, 48 ws: rw, 49 trusted: false, 50 known: set.New(), 51 quit: make(chan struct{}), 52 } 53 } 54 55 // start initiates the peer updater, periodically broadcasting the whisper packets 56 // into the network. 57 func (p *Peer) start() { 58 go p.update() 59 glog.V(logger.Debug).Infof("%v: whisper started", p.peer) 60 } 61 62 // stop terminates the peer updater, stopping message forwarding to it. 63 func (p *Peer) stop() { 64 close(p.quit) 65 glog.V(logger.Debug).Infof("%v: whisper stopped", p.peer) 66 } 67 68 // handshake sends the protocol initiation status message to the remote peer and 69 // verifies the remote status too. 70 func (p *Peer) handshake() error { 71 // Send the handshake status message asynchronously 72 errc := make(chan error, 1) 73 go func() { 74 errc <- p2p.Send(p.ws, statusCode, ProtocolVersion) 75 }() 76 // Fetch the remote status packet and verify protocol match 77 packet, err := p.ws.ReadMsg() 78 if err != nil { 79 return err 80 } 81 if packet.Code != statusCode { 82 return fmt.Errorf("peer sent %x before status packet", packet.Code) 83 } 84 s := rlp.NewStream(packet.Payload, uint64(packet.Size)) 85 peerVersion, err := s.Uint() 86 if err != nil { 87 return fmt.Errorf("bad status message: %v", err) 88 } 89 if peerVersion != ProtocolVersion { 90 return fmt.Errorf("protocol version mismatch %d != %d", peerVersion, ProtocolVersion) 91 } 92 // Wait until out own status is consumed too 93 if err := <-errc; err != nil { 94 return fmt.Errorf("failed to send status packet: %v", err) 95 } 96 return nil 97 } 98 99 // update executes periodic operations on the peer, including message transmission 100 // and expiration. 101 func (p *Peer) update() { 102 // Start the tickers for the updates 103 expire := time.NewTicker(expirationCycle) 104 transmit := time.NewTicker(transmissionCycle) 105 106 // Loop and transmit until termination is requested 107 for { 108 select { 109 case <-expire.C: 110 p.expire() 111 112 case <-transmit.C: 113 if err := p.broadcast(); err != nil { 114 glog.V(logger.Info).Infof("%v: broadcast failed: %v", p.peer, err) 115 return 116 } 117 118 case <-p.quit: 119 return 120 } 121 } 122 } 123 124 // mark marks an envelope known to the peer so that it won't be sent back. 125 func (peer *Peer) mark(envelope *Envelope) { 126 peer.known.Add(envelope.Hash()) 127 } 128 129 // marked checks if an envelope is already known to the remote peer. 130 func (peer *Peer) marked(envelope *Envelope) bool { 131 return peer.known.Has(envelope.Hash()) 132 } 133 134 // expire iterates over all the known envelopes in the host and removes all 135 // expired (unknown) ones from the known list. 136 func (peer *Peer) expire() { 137 // Assemble the list of available envelopes 138 available := set.NewNonTS() 139 for _, envelope := range peer.host.Envelopes() { 140 available.Add(envelope.Hash()) 141 } 142 // Cross reference availability with known status 143 unmark := make(map[common.Hash]struct{}) 144 peer.known.Each(func(v interface{}) bool { 145 if !available.Has(v.(common.Hash)) { 146 unmark[v.(common.Hash)] = struct{}{} 147 } 148 return true 149 }) 150 // Dump all known but unavailable 151 for hash := range unmark { 152 peer.known.Remove(hash) 153 } 154 } 155 156 // broadcast iterates over the collection of envelopes and transmits yet unknown 157 // ones over the network. 158 func (p *Peer) broadcast() error { 159 // Fetch the envelopes and collect the unknown ones 160 envelopes := p.host.Envelopes() 161 transmit := make([]*Envelope, 0, len(envelopes)) 162 for _, envelope := range envelopes { 163 if !p.marked(envelope) { 164 transmit = append(transmit, envelope) 165 p.mark(envelope) 166 } 167 } 168 if len(transmit) == 0 { 169 return nil 170 } 171 // Transmit the unknown batch (potentially empty) 172 if err := p2p.Send(p.ws, messagesCode, transmit); err != nil { 173 return err 174 } 175 glog.V(logger.Detail).Infoln(p.peer, "broadcasted", len(transmit), "message(s)") 176 return nil 177 } 178 179 func (p *Peer) ID() []byte { 180 id := p.peer.ID() 181 return id[:] 182 }