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  }