github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/whisper/whisperv6/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 whisperv6 18 19 import ( 20 "fmt" 21 "math" 22 "sync" 23 "time" 24 25 libp2p "github.com/libp2p/go-libp2p-peer" 26 "github.com/vntchain/go-vnt/common" 27 "github.com/vntchain/go-vnt/log" 28 "github.com/vntchain/go-vnt/rlp" 29 "github.com/vntchain/go-vnt/vntp2p" 30 set "gopkg.in/fatih/set.v0" 31 ) 32 33 // Peer represents a whisper protocol peer connection. 34 type Peer struct { 35 host *Whisper 36 peer *vntp2p.Peer 37 ws vntp2p.MsgReadWriter 38 39 trusted bool 40 powRequirement float64 41 bloomMu sync.Mutex 42 bloomFilter []byte 43 fullNode bool 44 45 known *set.Set // Messages already known by the peer to avoid wasting bandwidth 46 47 quit chan struct{} 48 } 49 50 // newPeer creates a new whisper peer object, but does not run the handshake itself. 51 func newPeer(host *Whisper, remote *vntp2p.Peer, rw vntp2p.MsgReadWriter) *Peer { 52 return &Peer{ 53 host: host, 54 peer: remote, 55 ws: rw, 56 trusted: false, 57 powRequirement: 0.0, 58 known: set.New(), 59 quit: make(chan struct{}), 60 bloomFilter: MakeFullNodeBloom(), 61 fullNode: true, 62 } 63 } 64 65 // start initiates the peer updater, periodically broadcasting the whisper packets 66 // into the network. 67 func (peer *Peer) start() { 68 go peer.update() 69 log.Trace("Whisper6 peer start", "peer", peer.ID()) 70 } 71 72 // stop terminates the peer updater, stopping message forwarding to it. 73 func (peer *Peer) stop() { 74 close(peer.quit) 75 log.Trace("Whisper6 peer stop", "peer", peer.ID()) 76 } 77 78 // handshake sends the protocol initiation status message to the remote peer and 79 // verifies the remote status too. 80 func (peer *Peer) handshake() error { 81 // Send the handshake status message asynchronously 82 errc := make(chan error, 1) 83 go func() { 84 pow := peer.host.MinPow() 85 powConverted := math.Float64bits(pow) 86 bloom := peer.host.BloomFilter() 87 errc <- vntp2p.SendItems(peer.ws, ProtocolName, statusCode, ProtocolVersion, powConverted, bloom) 88 }() 89 90 // Fetch the remote status packet and verify protocol match 91 packet, err := peer.ws.ReadMsg() 92 if err != nil { 93 return err 94 } 95 if packet.Body.Type != statusCode { 96 return fmt.Errorf("peer [%x] sent packet %x before status packet", peer.ID(), packet.Body.Type) 97 } 98 s := rlp.NewStream(packet.Body.Payload, uint64(packet.Body.PayloadSize)) 99 _, err = s.List() 100 if err != nil { 101 return fmt.Errorf("peer [%x] sent bad status message: %v", peer.ID(), err) 102 } 103 peerVersion, err := s.Uint() 104 if err != nil { 105 return fmt.Errorf("peer [%x] sent bad status message (unable to decode version): %v", peer.ID(), err) 106 } 107 if peerVersion != ProtocolVersion { 108 return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", peer.ID(), peerVersion, ProtocolVersion) 109 } 110 111 // only version is mandatory, subsequent parameters are optional 112 powRaw, err := s.Uint() 113 if err == nil { 114 pow := math.Float64frombits(powRaw) 115 if math.IsInf(pow, 0) || math.IsNaN(pow) || pow < 0.0 { 116 return fmt.Errorf("peer [%x] sent bad status message: invalid pow", peer.ID()) 117 } 118 peer.powRequirement = pow 119 120 var bloom []byte 121 err = s.Decode(&bloom) 122 if err == nil { 123 sz := len(bloom) 124 if sz != BloomFilterSize && sz != 0 { 125 return fmt.Errorf("peer [%x] sent bad status message: wrong bloom filter size %d", peer.ID(), sz) 126 } 127 peer.setBloomFilter(bloom) 128 } 129 } 130 131 if err := <-errc; err != nil { 132 return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err) 133 } 134 return nil 135 } 136 137 // update executes periodic operations on the peer, including message transmission 138 // and expiration. 139 func (peer *Peer) update() { 140 // Start the tickers for the updates 141 expire := time.NewTicker(expirationCycle) 142 transmit := time.NewTicker(transmissionCycle) 143 144 // Loop and transmit until termination is requested 145 for { 146 select { 147 case <-expire.C: 148 peer.expire() 149 150 case <-transmit.C: 151 if err := peer.broadcast(); err != nil { 152 log.Trace("broadcast failed", "reason", err, "peer", peer.ID()) 153 return 154 } 155 156 case <-peer.quit: 157 return 158 } 159 } 160 } 161 162 // mark marks an envelope known to the peer so that it won't be sent back. 163 func (peer *Peer) mark(envelope *Envelope) { 164 peer.known.Add(envelope.Hash()) 165 } 166 167 // marked checks if an envelope is already known to the remote peer. 168 func (peer *Peer) marked(envelope *Envelope) bool { 169 return peer.known.Has(envelope.Hash()) 170 } 171 172 // expire iterates over all the known envelopes in the host and removes all 173 // expired (unknown) ones from the known list. 174 func (peer *Peer) expire() { 175 unmark := make(map[common.Hash]struct{}) 176 peer.known.Each(func(v interface{}) bool { 177 if !peer.host.isEnvelopeCached(v.(common.Hash)) { 178 unmark[v.(common.Hash)] = struct{}{} 179 } 180 return true 181 }) 182 // Dump all known but no longer cached 183 for hash := range unmark { 184 peer.known.Remove(hash) 185 } 186 } 187 188 // broadcast iterates over the collection of envelopes and transmits yet unknown 189 // ones over the network. 190 func (peer *Peer) broadcast() error { 191 envelopes := peer.host.Envelopes() 192 bundle := make([]*Envelope, 0, len(envelopes)) 193 for _, envelope := range envelopes { 194 if !peer.marked(envelope) && envelope.PoW() >= peer.powRequirement && peer.bloomMatch(envelope) { 195 bundle = append(bundle, envelope) 196 } 197 } 198 199 if len(bundle) > 0 { 200 // transmit the batch of envelopes 201 if err := vntp2p.Send(peer.ws, ProtocolName, messagesCode, bundle); err != nil { 202 return err 203 } 204 205 // mark envelopes only if they were successfully sent 206 for _, e := range bundle { 207 peer.mark(e) 208 } 209 210 log.Trace("broadcast", "num. messages", len(bundle)) 211 } 212 return nil 213 } 214 215 // ID returns a peer's id 216 func (peer *Peer) ID() libp2p.ID { 217 id := peer.peer.RemoteID() 218 return id 219 } 220 221 func (peer *Peer) notifyAboutPowRequirementChange(pow float64) error { 222 i := math.Float64bits(pow) 223 return vntp2p.Send(peer.ws, ProtocolName, powRequirementCode, i) 224 } 225 226 func (peer *Peer) notifyAboutBloomFilterChange(bloom []byte) error { 227 return vntp2p.Send(peer.ws, ProtocolName, bloomFilterExCode, bloom) 228 } 229 230 func (peer *Peer) bloomMatch(env *Envelope) bool { 231 peer.bloomMu.Lock() 232 defer peer.bloomMu.Unlock() 233 return peer.fullNode || BloomFilterMatch(peer.bloomFilter, env.Bloom()) 234 } 235 236 func (peer *Peer) setBloomFilter(bloom []byte) { 237 peer.bloomMu.Lock() 238 defer peer.bloomMu.Unlock() 239 peer.bloomFilter = bloom 240 peer.fullNode = isFullNode(bloom) 241 if peer.fullNode && peer.bloomFilter == nil { 242 peer.bloomFilter = MakeFullNodeBloom() 243 } 244 } 245 246 func MakeFullNodeBloom() []byte { 247 bloom := make([]byte, BloomFilterSize) 248 for i := 0; i < BloomFilterSize; i++ { 249 bloom[i] = 0xFF 250 } 251 return bloom 252 }