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