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  }