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