github.com/codingfuture/orig-energi3@v0.8.4/swarm/network/discovery.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2018 The go-ethereum Authors 3 // This file is part of the Energi Core library. 4 // 5 // The Energi Core library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The Energi Core library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>. 17 18 package network 19 20 import ( 21 "context" 22 "fmt" 23 "sync" 24 25 "github.com/ethereum/go-ethereum/swarm/pot" 26 ) 27 28 // discovery bzz extension for requesting and relaying node address records 29 30 // Peer wraps BzzPeer and embeds Kademlia overlay connectivity driver 31 type Peer struct { 32 *BzzPeer 33 kad *Kademlia 34 sentPeers bool // whether we already sent peer closer to this address 35 mtx sync.RWMutex // 36 peers map[string]bool // tracks node records sent to the peer 37 depth uint8 // the proximity order advertised by remote as depth of saturation 38 } 39 40 // NewPeer constructs a discovery peer 41 func NewPeer(p *BzzPeer, kad *Kademlia) *Peer { 42 d := &Peer{ 43 kad: kad, 44 BzzPeer: p, 45 peers: make(map[string]bool), 46 } 47 // record remote as seen so we never send a peer its own record 48 d.seen(p.BzzAddr) 49 return d 50 } 51 52 // HandleMsg is the message handler that delegates incoming messages 53 func (d *Peer) HandleMsg(ctx context.Context, msg interface{}) error { 54 switch msg := msg.(type) { 55 56 case *peersMsg: 57 return d.handlePeersMsg(msg) 58 59 case *subPeersMsg: 60 return d.handleSubPeersMsg(msg) 61 62 default: 63 return fmt.Errorf("unknown message type: %T", msg) 64 } 65 } 66 67 // NotifyDepth sends a message to all connections if depth of saturation is changed 68 func NotifyDepth(depth uint8, kad *Kademlia) { 69 f := func(val *Peer, po int) bool { 70 val.NotifyDepth(depth) 71 return true 72 } 73 kad.EachConn(nil, 255, f) 74 } 75 76 // NotifyPeer informs all peers about a newly added node 77 func NotifyPeer(p *BzzAddr, k *Kademlia) { 78 f := func(val *Peer, po int) bool { 79 val.NotifyPeer(p, uint8(po)) 80 return true 81 } 82 k.EachConn(p.Address(), 255, f) 83 } 84 85 // NotifyPeer notifies the remote node (recipient) about a peer if 86 // the peer's PO is within the recipients advertised depth 87 // OR the peer is closer to the recipient than self 88 // unless already notified during the connection session 89 func (d *Peer) NotifyPeer(a *BzzAddr, po uint8) { 90 // immediately return 91 if (po < d.getDepth() && pot.ProxCmp(d.kad.BaseAddr(), d, a) != 1) || d.seen(a) { 92 return 93 } 94 resp := &peersMsg{ 95 Peers: []*BzzAddr{a}, 96 } 97 go d.Send(context.TODO(), resp) 98 } 99 100 // NotifyDepth sends a subPeers Msg to the receiver notifying them about 101 // a change in the depth of saturation 102 func (d *Peer) NotifyDepth(po uint8) { 103 go d.Send(context.TODO(), &subPeersMsg{Depth: po}) 104 } 105 106 /* 107 peersMsg is the message to pass peer information 108 It is always a response to a peersRequestMsg 109 110 The encoding of a peer address is identical the devp2p base protocol peers 111 messages: [IP, Port, NodeID], 112 Note that a node's FileStore address is not the NodeID but the hash of the NodeID. 113 114 TODO: 115 To mitigate against spurious peers messages, requests should be remembered 116 and correctness of responses should be checked 117 118 If the proxBin of peers in the response is incorrect the sender should be 119 disconnected 120 */ 121 122 // peersMsg encapsulates an array of peer addresses 123 // used for communicating about known peers 124 // relevant for bootstrapping connectivity and updating peersets 125 type peersMsg struct { 126 Peers []*BzzAddr 127 } 128 129 // String pretty prints a peersMsg 130 func (msg peersMsg) String() string { 131 return fmt.Sprintf("%T: %v", msg, msg.Peers) 132 } 133 134 // handlePeersMsg called by the protocol when receiving peerset (for target address) 135 // list of nodes ([]PeerAddr in peersMsg) is added to the overlay db using the 136 // Register interface method 137 func (d *Peer) handlePeersMsg(msg *peersMsg) error { 138 // register all addresses 139 if len(msg.Peers) == 0 { 140 return nil 141 } 142 143 for _, a := range msg.Peers { 144 d.seen(a) 145 NotifyPeer(a, d.kad) 146 } 147 return d.kad.Register(msg.Peers...) 148 } 149 150 // subPeers msg is communicating the depth of the overlay table of a peer 151 type subPeersMsg struct { 152 Depth uint8 153 } 154 155 // String returns the pretty printer 156 func (msg subPeersMsg) String() string { 157 return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth) 158 } 159 160 func (d *Peer) handleSubPeersMsg(msg *subPeersMsg) error { 161 if !d.sentPeers { 162 d.setDepth(msg.Depth) 163 var peers []*BzzAddr 164 d.kad.EachConn(d.Over(), 255, func(p *Peer, po int) bool { 165 if pob, _ := Pof(d, d.kad.BaseAddr(), 0); pob > po { 166 return false 167 } 168 if !d.seen(p.BzzAddr) { 169 peers = append(peers, p.BzzAddr) 170 } 171 return true 172 }) 173 if len(peers) > 0 { 174 go d.Send(context.TODO(), &peersMsg{Peers: peers}) 175 } 176 } 177 d.sentPeers = true 178 return nil 179 } 180 181 // seen takes an peer address and checks if it was sent to a peer already 182 // if not, marks the peer as sent 183 func (d *Peer) seen(p *BzzAddr) bool { 184 d.mtx.Lock() 185 defer d.mtx.Unlock() 186 k := string(p.Address()) 187 if d.peers[k] { 188 return true 189 } 190 d.peers[k] = true 191 return false 192 } 193 194 func (d *Peer) getDepth() uint8 { 195 d.mtx.RLock() 196 defer d.mtx.RUnlock() 197 return d.depth 198 } 199 200 func (d *Peer) setDepth(depth uint8) { 201 d.mtx.Lock() 202 defer d.mtx.Unlock() 203 d.depth = depth 204 }