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