github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/network/protocol.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 "errors" 22 "fmt" 23 "math/rand" 24 "sync" 25 "time" 26 27 "github.com/ethereum/go-ethereum/p2p" 28 "github.com/ethereum/go-ethereum/p2p/enode" 29 "github.com/ethereum/go-ethereum/p2p/protocols" 30 "github.com/ethereum/go-ethereum/rpc" 31 "github.com/ethereum/go-ethereum/swarm/log" 32 "github.com/ethereum/go-ethereum/swarm/state" 33 ) 34 35 const ( 36 DefaultNetworkID = 3 37 // timeout for waiting 38 bzzHandshakeTimeout = 3000 * time.Millisecond 39 ) 40 41 var DefaultTestNetworkID = rand.Uint64() 42 43 // BzzSpec is the spec of the generic swarm handshake 44 var BzzSpec = &protocols.Spec{ 45 Name: "bzz", 46 Version: 8, 47 MaxMsgSize: 10 * 1024 * 1024, 48 Messages: []interface{}{ 49 HandshakeMsg{}, 50 }, 51 } 52 53 // DiscoverySpec is the spec for the bzz discovery subprotocols 54 var DiscoverySpec = &protocols.Spec{ 55 Name: "hive", 56 Version: 8, 57 MaxMsgSize: 10 * 1024 * 1024, 58 Messages: []interface{}{ 59 peersMsg{}, 60 subPeersMsg{}, 61 }, 62 } 63 64 // BzzConfig captures the config params used by the hive 65 type BzzConfig struct { 66 OverlayAddr []byte // base address of the overlay network 67 UnderlayAddr []byte // node's underlay address 68 HiveParams *HiveParams 69 NetworkID uint64 70 LightNode bool 71 BootnodeMode bool 72 } 73 74 // Bzz is the swarm protocol bundle 75 type Bzz struct { 76 *Hive 77 NetworkID uint64 78 LightNode bool 79 localAddr *BzzAddr 80 mtx sync.Mutex 81 handshakes map[enode.ID]*HandshakeMsg 82 streamerSpec *protocols.Spec 83 streamerRun func(*BzzPeer) error 84 } 85 86 // NewBzz is the swarm protocol constructor 87 // arguments 88 // * bzz config 89 // * overlay driver 90 // * peer store 91 func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec *protocols.Spec, streamerRun func(*BzzPeer) error) *Bzz { 92 bzz := &Bzz{ 93 Hive: NewHive(config.HiveParams, kad, store), 94 NetworkID: config.NetworkID, 95 LightNode: config.LightNode, 96 localAddr: &BzzAddr{config.OverlayAddr, config.UnderlayAddr}, 97 handshakes: make(map[enode.ID]*HandshakeMsg), 98 streamerRun: streamerRun, 99 streamerSpec: streamerSpec, 100 } 101 102 if config.BootnodeMode { 103 bzz.streamerRun = nil 104 bzz.streamerSpec = nil 105 } 106 107 return bzz 108 } 109 110 // UpdateLocalAddr updates underlayaddress of the running node 111 func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *BzzAddr { 112 b.localAddr = b.localAddr.Update(&BzzAddr{ 113 UAddr: byteaddr, 114 OAddr: b.localAddr.OAddr, 115 }) 116 return b.localAddr 117 } 118 119 // NodeInfo returns the node's overlay address 120 func (b *Bzz) NodeInfo() interface{} { 121 return b.localAddr.Address() 122 } 123 124 // Protocols return the protocols swarm offers 125 // Bzz implements the node.Service interface 126 // * handshake/hive 127 // * discovery 128 func (b *Bzz) Protocols() []p2p.Protocol { 129 protocol := []p2p.Protocol{ 130 { 131 Name: BzzSpec.Name, 132 Version: BzzSpec.Version, 133 Length: BzzSpec.Length(), 134 Run: b.runBzz, 135 NodeInfo: b.NodeInfo, 136 }, 137 { 138 Name: DiscoverySpec.Name, 139 Version: DiscoverySpec.Version, 140 Length: DiscoverySpec.Length(), 141 Run: b.RunProtocol(DiscoverySpec, b.Hive.Run), 142 NodeInfo: b.Hive.NodeInfo, 143 PeerInfo: b.Hive.PeerInfo, 144 }, 145 } 146 if b.streamerSpec != nil && b.streamerRun != nil { 147 protocol = append(protocol, p2p.Protocol{ 148 Name: b.streamerSpec.Name, 149 Version: b.streamerSpec.Version, 150 Length: b.streamerSpec.Length(), 151 Run: b.RunProtocol(b.streamerSpec, b.streamerRun), 152 }) 153 } 154 return protocol 155 } 156 157 // APIs returns the APIs offered by bzz 158 // * hive 159 // Bzz implements the node.Service interface 160 func (b *Bzz) APIs() []rpc.API { 161 return []rpc.API{{ 162 Namespace: "hive", 163 Version: "3.0", 164 Service: b.Hive, 165 }} 166 } 167 168 // RunProtocol is a wrapper for swarm subprotocols 169 // returns a p2p protocol run function that can be assigned to p2p.Protocol#Run field 170 // arguments: 171 // * p2p protocol spec 172 // * run function taking BzzPeer as argument 173 // this run function is meant to block for the duration of the protocol session 174 // on return the session is terminated and the peer is disconnected 175 // the protocol waits for the bzz handshake is negotiated 176 // the overlay address on the BzzPeer is set from the remote handshake 177 func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(*p2p.Peer, p2p.MsgReadWriter) error { 178 return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { 179 // wait for the bzz protocol to perform the handshake 180 handshake, _ := b.GetOrCreateHandshake(p.ID()) 181 defer b.removeHandshake(p.ID()) 182 select { 183 case <-handshake.done: 184 case <-time.After(bzzHandshakeTimeout): 185 return fmt.Errorf("%08x: %s protocol timeout waiting for handshake on %08x", b.BaseAddr()[:4], spec.Name, p.ID().Bytes()[:4]) 186 } 187 if handshake.err != nil { 188 return fmt.Errorf("%08x: %s protocol closed: %v", b.BaseAddr()[:4], spec.Name, handshake.err) 189 } 190 // the handshake has succeeded so construct the BzzPeer and run the protocol 191 peer := &BzzPeer{ 192 Peer: protocols.NewPeer(p, rw, spec), 193 BzzAddr: handshake.peerAddr, 194 lastActive: time.Now(), 195 LightNode: handshake.LightNode, 196 } 197 198 log.Debug("peer created", "addr", handshake.peerAddr.String()) 199 200 return run(peer) 201 } 202 } 203 204 // performHandshake implements the negotiation of the bzz handshake 205 // shared among swarm subprotocols 206 func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error { 207 ctx, cancel := context.WithTimeout(context.Background(), bzzHandshakeTimeout) 208 defer func() { 209 close(handshake.done) 210 cancel() 211 }() 212 rsh, err := p.Handshake(ctx, handshake, b.checkHandshake) 213 if err != nil { 214 handshake.err = err 215 return err 216 } 217 handshake.peerAddr = rsh.(*HandshakeMsg).Addr 218 handshake.LightNode = rsh.(*HandshakeMsg).LightNode 219 return nil 220 } 221 222 // runBzz is the p2p protocol run function for the bzz base protocol 223 // that negotiates the bzz handshake 224 func (b *Bzz) runBzz(p *p2p.Peer, rw p2p.MsgReadWriter) error { 225 handshake, _ := b.GetOrCreateHandshake(p.ID()) 226 if !<-handshake.init { 227 return fmt.Errorf("%08x: bzz already started on peer %08x", b.localAddr.Over()[:4], p.ID().Bytes()[:4]) 228 } 229 close(handshake.init) 230 defer b.removeHandshake(p.ID()) 231 peer := protocols.NewPeer(p, rw, BzzSpec) 232 err := b.performHandshake(peer, handshake) 233 if err != nil { 234 log.Warn(fmt.Sprintf("%08x: handshake failed with remote peer %08x: %v", b.localAddr.Over()[:4], p.ID().Bytes()[:4], err)) 235 236 return err 237 } 238 // fail if we get another handshake 239 msg, err := rw.ReadMsg() 240 if err != nil { 241 return err 242 } 243 msg.Discard() 244 return errors.New("received multiple handshakes") 245 } 246 247 // BzzPeer is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer) 248 // implements the Peer interface and all interfaces Peer implements: Addr, OverlayPeer 249 type BzzPeer struct { 250 *protocols.Peer // represents the connection for online peers 251 *BzzAddr // remote address -> implements Addr interface = protocols.Peer 252 lastActive time.Time // time is updated whenever mutexes are releasing 253 LightNode bool 254 } 255 256 func NewBzzPeer(p *protocols.Peer) *BzzPeer { 257 return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())} 258 } 259 260 // ID returns the peer's underlay node identifier. 261 func (p *BzzPeer) ID() enode.ID { 262 // This is here to resolve a method tie: both protocols.Peer and BzzAddr are embedded 263 // into the struct and provide ID(). The protocols.Peer version is faster, ensure it 264 // gets used. 265 return p.Peer.ID() 266 } 267 268 /* 269 Handshake 270 271 * Version: 8 byte integer version of the protocol 272 * NetworkID: 8 byte integer network identifier 273 * Addr: the address advertised by the node including underlay and overlay connecctions 274 */ 275 type HandshakeMsg struct { 276 Version uint64 277 NetworkID uint64 278 Addr *BzzAddr 279 LightNode bool 280 281 // peerAddr is the address received in the peer handshake 282 peerAddr *BzzAddr 283 284 init chan bool 285 done chan struct{} 286 err error 287 } 288 289 // String pretty prints the handshake 290 func (bh *HandshakeMsg) String() string { 291 return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, LightNode: %v, peerAddr: %v", bh.Version, bh.NetworkID, bh.Addr, bh.LightNode, bh.peerAddr) 292 } 293 294 // Perform initiates the handshake and validates the remote handshake message 295 func (b *Bzz) checkHandshake(hs interface{}) error { 296 rhs := hs.(*HandshakeMsg) 297 if rhs.NetworkID != b.NetworkID { 298 return fmt.Errorf("network id mismatch %d (!= %d)", rhs.NetworkID, b.NetworkID) 299 } 300 if rhs.Version != uint64(BzzSpec.Version) { 301 return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, BzzSpec.Version) 302 } 303 return nil 304 } 305 306 // removeHandshake removes handshake for peer with peerID 307 // from the bzz handshake store 308 func (b *Bzz) removeHandshake(peerID enode.ID) { 309 b.mtx.Lock() 310 defer b.mtx.Unlock() 311 delete(b.handshakes, peerID) 312 } 313 314 // GetHandshake returns the bzz handhake that the remote peer with peerID sent 315 func (b *Bzz) GetOrCreateHandshake(peerID enode.ID) (*HandshakeMsg, bool) { 316 b.mtx.Lock() 317 defer b.mtx.Unlock() 318 handshake, found := b.handshakes[peerID] 319 if !found { 320 handshake = &HandshakeMsg{ 321 Version: uint64(BzzSpec.Version), 322 NetworkID: b.NetworkID, 323 Addr: b.localAddr, 324 LightNode: b.LightNode, 325 init: make(chan bool, 1), 326 done: make(chan struct{}), 327 } 328 // when handhsake is first created for a remote peer 329 // it is initialised with the init 330 handshake.init <- true 331 b.handshakes[peerID] = handshake 332 } 333 334 return handshake, found 335 }