github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/swarm/network/discovery.go (about) 1 // Copyright 2016 The go-athereum Authors 2 // This file is part of the go-athereum library. 3 // 4 // The go-athereum 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-athereum 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-athereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package network 18 19 import ( 20 "fmt" 21 "sync" 22 23 "github.com/athereum/go-athereum/swarm/pot" 24 ) 25 26 // discovery bzz extension for requesting and relaying node address records 27 28 // discPeer wraps BzzPeer and embeds an Overlay connectivity driver 29 type discPeer struct { 30 *BzzPeer 31 overlay Overlay 32 sentPeers bool // whather we already sent peer closer to this address 33 mtx sync.RWMutex 34 peers map[string]bool // tracks node records sent to the peer 35 depth uint8 // the proximity order advertised by remote as depth of saturation 36 } 37 38 // NewDiscovery constructs a discovery peer 39 func newDiscovery(p *BzzPeer, o Overlay) *discPeer { 40 d := &discPeer{ 41 overlay: o, 42 BzzPeer: p, 43 peers: make(map[string]bool), 44 } 45 // record remote as seen so we never send a peer its own record 46 d.seen(d) 47 return d 48 } 49 50 // HandleMsg is the message handler that delegates incoming messages 51 func (d *discPeer) HandleMsg(msg interface{}) error { 52 switch msg := msg.(type) { 53 54 case *peersMsg: 55 return d.handlePeersMsg(msg) 56 57 case *subPeersMsg: 58 return d.handleSubPeersMsg(msg) 59 60 default: 61 return fmt.Errorf("unknown message type: %T", msg) 62 } 63 } 64 65 // NotifyDepth sends a message to all connections if depth of saturation is changed 66 func NotifyDepth(depth uint8, h Overlay) { 67 f := func(val OverlayConn, po int, _ bool) bool { 68 dp, ok := val.(*discPeer) 69 if ok { 70 dp.NotifyDepth(depth) 71 } 72 return true 73 } 74 h.EachConn(nil, 255, f) 75 } 76 77 // NotifyPeer informs all peers about a newly added node 78 func NotifyPeer(p OverlayAddr, k Overlay) { 79 f := func(val OverlayConn, po int, _ bool) bool { 80 dp, ok := val.(*discPeer) 81 if ok { 82 dp.NotifyPeer(p, uint8(po)) 83 } 84 return true 85 } 86 k.EachConn(p.Address(), 255, f) 87 } 88 89 // NotifyPeer notifies the remote node (recipient) about a peer if 90 // the peer's PO is within the recipients advertised depth 91 // OR the peer is closer to the recipient than self 92 // unless already notified during the connection session 93 func (d *discPeer) NotifyPeer(a OverlayAddr, po uint8) { 94 // immediately return 95 if (po < d.getDepth() && pot.ProxCmp(d.localAddr, d, a) != 1) || d.seen(a) { 96 return 97 } 98 // log.Trace(fmt.Sprintf("%08x peer %08x notified of peer %08x", d.localAddr.Over()[:4], d.Address()[:4], a.Address()[:4])) 99 resp := &peersMsg{ 100 Peers: []*BzzAddr{ToAddr(a)}, 101 } 102 go d.Send(resp) 103 } 104 105 // NotifyDepth sends a subPeers Msg to the receiver notifying them about 106 // a change in the depth of saturation 107 func (d *discPeer) NotifyDepth(po uint8) { 108 // log.Trace(fmt.Sprintf("%08x peer %08x notified of new depth %v", d.localAddr.Over()[:4], d.Address()[:4], po)) 109 go d.Send(&subPeersMsg{Depth: po}) 110 } 111 112 /* 113 peersMsg is the message to pass peer information 114 It is always a response to a peersRequestMsg 115 116 The encoding of a peer address is identical the devp2p base protocol peers 117 messages: [IP, Port, NodeID], 118 Note that a node's FileStore address is not the NodeID but the hash of the NodeID. 119 120 TODO: 121 To mitigate against spurious peers messages, requests should be remembered 122 and correctness of responses should be checked 123 124 If the proxBin of peers in the response is incorrect the sender should be 125 disconnected 126 */ 127 128 // peersMsg encapsulates an array of peer addresses 129 // used for communicating about known peers 130 // relevant for bootstrapping connectivity and updating peersets 131 type peersMsg struct { 132 Peers []*BzzAddr 133 } 134 135 // String pretty prints a peersMsg 136 func (msg peersMsg) String() string { 137 return fmt.Sprintf("%T: %v", msg, msg.Peers) 138 } 139 140 // handlePeersMsg called by the protocol when receiving peerset (for target address) 141 // list of nodes ([]PeerAddr in peersMsg) is added to the overlay db using the 142 // Register interface method 143 func (d *discPeer) handlePeersMsg(msg *peersMsg) error { 144 // register all addresses 145 if len(msg.Peers) == 0 { 146 return nil 147 } 148 149 for _, a := range msg.Peers { 150 d.seen(a) 151 NotifyPeer(a, d.overlay) 152 } 153 return d.overlay.Register(toOverlayAddrs(msg.Peers...)) 154 } 155 156 // subPeers msg is communicating the depth/sharpness/focus of the overlay table of a peer 157 type subPeersMsg struct { 158 Depth uint8 159 } 160 161 // String returns the pretty printer 162 func (msg subPeersMsg) String() string { 163 return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth) 164 } 165 166 func (d *discPeer) handleSubPeersMsg(msg *subPeersMsg) error { 167 if !d.sentPeers { 168 d.setDepth(msg.Depth) 169 var peers []*BzzAddr 170 d.overlay.EachConn(d.Over(), 255, func(p OverlayConn, po int, isproxbin bool) bool { 171 if pob, _ := pof(d, d.localAddr, 0); pob > po { 172 return false 173 } 174 if !d.seen(p) { 175 peers = append(peers, ToAddr(p.Off())) 176 } 177 return true 178 }) 179 if len(peers) > 0 { 180 // log.Debug(fmt.Sprintf("%08x: %v peers sent to %v", d.overlay.BaseAddr(), len(peers), d)) 181 go d.Send(&peersMsg{Peers: peers}) 182 } 183 } 184 d.sentPeers = true 185 return nil 186 } 187 188 // seen takes an Overlay peer and checks if it was sent to a peer already 189 // if not, marks the peer as sent 190 func (d *discPeer) seen(p OverlayPeer) bool { 191 d.mtx.Lock() 192 defer d.mtx.Unlock() 193 k := string(p.Address()) 194 if d.peers[k] { 195 return true 196 } 197 d.peers[k] = true 198 return false 199 } 200 201 func (d *discPeer) getDepth() uint8 { 202 d.mtx.RLock() 203 defer d.mtx.RUnlock() 204 return d.depth 205 } 206 func (d *discPeer) setDepth(depth uint8) { 207 d.mtx.Lock() 208 defer d.mtx.Unlock() 209 d.depth = depth 210 }