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