github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/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 "net" 24 "sync" 25 "time" 26 27 "github.com/FusionFoundation/efsn/crypto" 28 "github.com/FusionFoundation/efsn/p2p" 29 "github.com/FusionFoundation/efsn/p2p/discover" 30 "github.com/FusionFoundation/efsn/p2p/protocols" 31 "github.com/FusionFoundation/efsn/rpc" 32 "github.com/FusionFoundation/efsn/swarm/log" 33 "github.com/FusionFoundation/efsn/swarm/state" 34 ) 35 36 const ( 37 DefaultNetworkID = 3 38 // ProtocolMaxMsgSize maximum allowed message size 39 ProtocolMaxMsgSize = 10 * 1024 * 1024 40 // timeout for waiting 41 bzzHandshakeTimeout = 3000 * time.Millisecond 42 ) 43 44 // BzzSpec is the spec of the generic swarm handshake 45 var BzzSpec = &protocols.Spec{ 46 Name: "bzz", 47 Version: 7, 48 MaxMsgSize: 10 * 1024 * 1024, 49 Messages: []interface{}{ 50 HandshakeMsg{}, 51 }, 52 } 53 54 // DiscoverySpec is the spec for the bzz discovery subprotocols 55 var DiscoverySpec = &protocols.Spec{ 56 Name: "hive", 57 Version: 6, 58 MaxMsgSize: 10 * 1024 * 1024, 59 Messages: []interface{}{ 60 peersMsg{}, 61 subPeersMsg{}, 62 }, 63 } 64 65 // BzzConfig captures the config params used by the hive 66 type BzzConfig struct { 67 OverlayAddr []byte // base address of the overlay network 68 UnderlayAddr []byte // node's underlay address 69 HiveParams *HiveParams 70 NetworkID uint64 71 LightNode 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[discover.NodeID]*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 return &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[discover.NodeID]*HandshakeMsg), 98 streamerRun: streamerRun, 99 streamerSpec: streamerSpec, 100 } 101 } 102 103 // UpdateLocalAddr updates underlayaddress of the running node 104 func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *BzzAddr { 105 b.localAddr = b.localAddr.Update(&BzzAddr{ 106 UAddr: byteaddr, 107 OAddr: b.localAddr.OAddr, 108 }) 109 return b.localAddr 110 } 111 112 // NodeInfo returns the node's overlay address 113 func (b *Bzz) NodeInfo() interface{} { 114 return b.localAddr.Address() 115 } 116 117 // Protocols return the protocols swarm offers 118 // Bzz implements the node.Service interface 119 // * handshake/hive 120 // * discovery 121 func (b *Bzz) Protocols() []p2p.Protocol { 122 protocol := []p2p.Protocol{ 123 { 124 Name: BzzSpec.Name, 125 Version: BzzSpec.Version, 126 Length: BzzSpec.Length(), 127 Run: b.runBzz, 128 NodeInfo: b.NodeInfo, 129 }, 130 { 131 Name: DiscoverySpec.Name, 132 Version: DiscoverySpec.Version, 133 Length: DiscoverySpec.Length(), 134 Run: b.RunProtocol(DiscoverySpec, b.Hive.Run), 135 NodeInfo: b.Hive.NodeInfo, 136 PeerInfo: b.Hive.PeerInfo, 137 }, 138 } 139 if b.streamerSpec != nil && b.streamerRun != nil { 140 protocol = append(protocol, p2p.Protocol{ 141 Name: b.streamerSpec.Name, 142 Version: b.streamerSpec.Version, 143 Length: b.streamerSpec.Length(), 144 Run: b.RunProtocol(b.streamerSpec, b.streamerRun), 145 }) 146 } 147 return protocol 148 } 149 150 // APIs returns the APIs offered by bzz 151 // * hive 152 // Bzz implements the node.Service interface 153 func (b *Bzz) APIs() []rpc.API { 154 return []rpc.API{{ 155 Namespace: "hive", 156 Version: "3.0", 157 Service: b.Hive, 158 }} 159 } 160 161 // RunProtocol is a wrapper for swarm subprotocols 162 // returns a p2p protocol run function that can be assigned to p2p.Protocol#Run field 163 // arguments: 164 // * p2p protocol spec 165 // * run function taking BzzPeer as argument 166 // this run function is meant to block for the duration of the protocol session 167 // on return the session is terminated and the peer is disconnected 168 // the protocol waits for the bzz handshake is negotiated 169 // the overlay address on the BzzPeer is set from the remote handshake 170 func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(*p2p.Peer, p2p.MsgReadWriter) error { 171 return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { 172 // wait for the bzz protocol to perform the handshake 173 handshake, _ := b.GetHandshake(p.ID()) 174 defer b.removeHandshake(p.ID()) 175 select { 176 case <-handshake.done: 177 case <-time.After(bzzHandshakeTimeout): 178 return fmt.Errorf("%08x: %s protocol timeout waiting for handshake on %08x", b.BaseAddr()[:4], spec.Name, p.ID().Bytes()[:4]) 179 } 180 if handshake.err != nil { 181 return fmt.Errorf("%08x: %s protocol closed: %v", b.BaseAddr()[:4], spec.Name, handshake.err) 182 } 183 // the handshake has succeeded so construct the BzzPeer and run the protocol 184 peer := &BzzPeer{ 185 Peer: protocols.NewPeer(p, rw, spec), 186 localAddr: b.localAddr, 187 BzzAddr: handshake.peerAddr, 188 lastActive: time.Now(), 189 LightNode: handshake.LightNode, 190 } 191 192 log.Debug("peer created", "addr", handshake.peerAddr.String()) 193 194 return run(peer) 195 } 196 } 197 198 // performHandshake implements the negotiation of the bzz handshake 199 // shared among swarm subprotocols 200 func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error { 201 ctx, cancel := context.WithTimeout(context.Background(), bzzHandshakeTimeout) 202 defer func() { 203 close(handshake.done) 204 cancel() 205 }() 206 rsh, err := p.Handshake(ctx, handshake, b.checkHandshake) 207 if err != nil { 208 handshake.err = err 209 return err 210 } 211 handshake.peerAddr = rsh.(*HandshakeMsg).Addr 212 handshake.LightNode = rsh.(*HandshakeMsg).LightNode 213 return nil 214 } 215 216 // runBzz is the p2p protocol run function for the bzz base protocol 217 // that negotiates the bzz handshake 218 func (b *Bzz) runBzz(p *p2p.Peer, rw p2p.MsgReadWriter) error { 219 handshake, _ := b.GetHandshake(p.ID()) 220 if !<-handshake.init { 221 return fmt.Errorf("%08x: bzz already started on peer %08x", b.localAddr.Over()[:4], ToOverlayAddr(p.ID().Bytes())[:4]) 222 } 223 close(handshake.init) 224 defer b.removeHandshake(p.ID()) 225 peer := protocols.NewPeer(p, rw, BzzSpec) 226 err := b.performHandshake(peer, handshake) 227 if err != nil { 228 log.Warn(fmt.Sprintf("%08x: handshake failed with remote peer %08x: %v", b.localAddr.Over()[:4], ToOverlayAddr(p.ID().Bytes())[:4], err)) 229 230 return err 231 } 232 // fail if we get another handshake 233 msg, err := rw.ReadMsg() 234 if err != nil { 235 return err 236 } 237 msg.Discard() 238 return errors.New("received multiple handshakes") 239 } 240 241 // BzzPeer is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer) 242 // implements the Peer interface and all interfaces Peer implements: Addr, OverlayPeer 243 type BzzPeer struct { 244 *protocols.Peer // represents the connection for online peers 245 localAddr *BzzAddr // local Peers address 246 *BzzAddr // remote address -> implements Addr interface = protocols.Peer 247 lastActive time.Time // time is updated whenever mutexes are releasing 248 LightNode bool 249 } 250 251 func NewBzzPeer(p *protocols.Peer, addr *BzzAddr) *BzzPeer { 252 return &BzzPeer{ 253 Peer: p, 254 localAddr: addr, 255 BzzAddr: NewAddrFromNodeID(p.ID()), 256 } 257 } 258 259 // LastActive returns the time the peer was last active 260 func (p *BzzPeer) LastActive() time.Time { 261 return p.lastActive 262 } 263 264 /* 265 Handshake 266 267 * Version: 8 byte integer version of the protocol 268 * NetworkID: 8 byte integer network identifier 269 * Addr: the address advertised by the node including underlay and overlay connecctions 270 */ 271 type HandshakeMsg struct { 272 Version uint64 273 NetworkID uint64 274 Addr *BzzAddr 275 LightNode bool 276 277 // peerAddr is the address received in the peer handshake 278 peerAddr *BzzAddr 279 280 init chan bool 281 done chan struct{} 282 err error 283 } 284 285 // String pretty prints the handshake 286 func (bh *HandshakeMsg) String() string { 287 return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, LightNode: %v, peerAddr: %v", bh.Version, bh.NetworkID, bh.Addr, bh.LightNode, bh.peerAddr) 288 } 289 290 // Perform initiates the handshake and validates the remote handshake message 291 func (b *Bzz) checkHandshake(hs interface{}) error { 292 rhs := hs.(*HandshakeMsg) 293 if rhs.NetworkID != b.NetworkID { 294 return fmt.Errorf("network id mismatch %d (!= %d)", rhs.NetworkID, b.NetworkID) 295 } 296 if rhs.Version != uint64(BzzSpec.Version) { 297 return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, BzzSpec.Version) 298 } 299 return nil 300 } 301 302 // removeHandshake removes handshake for peer with peerID 303 // from the bzz handshake store 304 func (b *Bzz) removeHandshake(peerID discover.NodeID) { 305 b.mtx.Lock() 306 defer b.mtx.Unlock() 307 delete(b.handshakes, peerID) 308 } 309 310 // GetHandshake returns the bzz handhake that the remote peer with peerID sent 311 func (b *Bzz) GetHandshake(peerID discover.NodeID) (*HandshakeMsg, bool) { 312 b.mtx.Lock() 313 defer b.mtx.Unlock() 314 handshake, found := b.handshakes[peerID] 315 if !found { 316 handshake = &HandshakeMsg{ 317 Version: uint64(BzzSpec.Version), 318 NetworkID: b.NetworkID, 319 Addr: b.localAddr, 320 LightNode: b.LightNode, 321 init: make(chan bool, 1), 322 done: make(chan struct{}), 323 } 324 // when handhsake is first created for a remote peer 325 // it is initialised with the init 326 handshake.init <- true 327 b.handshakes[peerID] = handshake 328 } 329 330 return handshake, found 331 } 332 333 // BzzAddr implements the PeerAddr interface 334 type BzzAddr struct { 335 OAddr []byte 336 UAddr []byte 337 } 338 339 // Address implements OverlayPeer interface to be used in Overlay 340 func (a *BzzAddr) Address() []byte { 341 return a.OAddr 342 } 343 344 // Over returns the overlay address 345 func (a *BzzAddr) Over() []byte { 346 return a.OAddr 347 } 348 349 // Under returns the underlay address 350 func (a *BzzAddr) Under() []byte { 351 return a.UAddr 352 } 353 354 // ID returns the nodeID from the underlay enode address 355 func (a *BzzAddr) ID() discover.NodeID { 356 return discover.MustParseNode(string(a.UAddr)).ID 357 } 358 359 // Update updates the underlay address of a peer record 360 func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { 361 return &BzzAddr{a.OAddr, na.UAddr} 362 } 363 364 // String pretty prints the address 365 func (a *BzzAddr) String() string { 366 return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) 367 } 368 369 // RandomAddr is a utility method generating an address from a public key 370 func RandomAddr() *BzzAddr { 371 key, err := crypto.GenerateKey() 372 if err != nil { 373 panic("unable to generate key") 374 } 375 pubkey := crypto.FromECDSAPub(&key.PublicKey) 376 var id discover.NodeID 377 copy(id[:], pubkey[1:]) 378 return NewAddrFromNodeID(id) 379 } 380 381 // NewNodeIDFromAddr transforms the underlay address to an adapters.NodeID 382 func NewNodeIDFromAddr(addr *BzzAddr) discover.NodeID { 383 log.Info(fmt.Sprintf("uaddr=%s", string(addr.UAddr))) 384 node := discover.MustParseNode(string(addr.UAddr)) 385 return node.ID 386 } 387 388 // NewAddrFromNodeID constucts a BzzAddr from a discover.NodeID 389 // the overlay address is derived as the hash of the nodeID 390 func NewAddrFromNodeID(id discover.NodeID) *BzzAddr { 391 return &BzzAddr{ 392 OAddr: ToOverlayAddr(id.Bytes()), 393 UAddr: []byte(discover.NewNode(id, net.IP{127, 0, 0, 1}, 30303, 30303).String()), 394 } 395 } 396 397 // NewAddrFromNodeIDAndPort constucts a BzzAddr from a discover.NodeID and port uint16 398 // the overlay address is derived as the hash of the nodeID 399 func NewAddrFromNodeIDAndPort(id discover.NodeID, host net.IP, port uint16) *BzzAddr { 400 return &BzzAddr{ 401 OAddr: ToOverlayAddr(id.Bytes()), 402 UAddr: []byte(discover.NewNode(id, host, port, port).String()), 403 } 404 } 405 406 // ToOverlayAddr creates an overlayaddress from a byte slice 407 func ToOverlayAddr(id []byte) []byte { 408 return crypto.Keccak256(id) 409 }