github.com/codingfuture/orig-energi3@v0.8.4/swarm/network/protocol.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2016 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 "errors" 23 "fmt" 24 "net" 25 "sync" 26 "time" 27 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/p2p" 30 "github.com/ethereum/go-ethereum/p2p/enode" 31 "github.com/ethereum/go-ethereum/p2p/protocols" 32 "github.com/ethereum/go-ethereum/rpc" 33 "github.com/ethereum/go-ethereum/swarm/log" 34 "github.com/ethereum/go-ethereum/swarm/state" 35 ) 36 37 const ( 38 DefaultNetworkID = 3 39 // timeout for waiting 40 bzzHandshakeTimeout = 3000 * time.Millisecond 41 ) 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 } 336 337 // BzzAddr implements the PeerAddr interface 338 type BzzAddr struct { 339 OAddr []byte 340 UAddr []byte 341 } 342 343 // Address implements OverlayPeer interface to be used in Overlay. 344 func (a *BzzAddr) Address() []byte { 345 return a.OAddr 346 } 347 348 // Over returns the overlay address. 349 func (a *BzzAddr) Over() []byte { 350 return a.OAddr 351 } 352 353 // Under returns the underlay address. 354 func (a *BzzAddr) Under() []byte { 355 return a.UAddr 356 } 357 358 // ID returns the node identifier in the underlay. 359 func (a *BzzAddr) ID() enode.ID { 360 n, err := enode.ParseV4(string(a.UAddr)) 361 if err != nil { 362 return enode.ID{} 363 } 364 return n.ID() 365 } 366 367 // Update updates the underlay address of a peer record 368 func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { 369 return &BzzAddr{a.OAddr, na.UAddr} 370 } 371 372 // String pretty prints the address 373 func (a *BzzAddr) String() string { 374 return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) 375 } 376 377 // RandomAddr is a utility method generating an address from a public key 378 func RandomAddr() *BzzAddr { 379 key, err := crypto.GenerateKey() 380 if err != nil { 381 panic("unable to generate key") 382 } 383 node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 39797, 39797) 384 return NewAddr(node) 385 } 386 387 // NewAddr constucts a BzzAddr from a node record. 388 func NewAddr(node *enode.Node) *BzzAddr { 389 return &BzzAddr{OAddr: node.ID().Bytes(), UAddr: []byte(node.String())} 390 }