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