github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/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/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/p2p"
    29  	"github.com/ethereum/go-ethereum/p2p/discover"
    30  	"github.com/ethereum/go-ethereum/p2p/protocols"
    31  	"github.com/ethereum/go-ethereum/rpc"
    32  	"github.com/ethereum/go-ethereum/swarm/log"
    33  	"github.com/ethereum/go-ethereum/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:    5,
    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:    5,
    58  	MaxMsgSize: 10 * 1024 * 1024,
    59  	Messages: []interface{}{
    60  		peersMsg{},
    61  		subPeersMsg{},
    62  	},
    63  }
    64  
    65  // Addr interface that peerPool needs
    66  type Addr interface {
    67  	OverlayPeer
    68  	Over() []byte
    69  	Under() []byte
    70  	String() string
    71  	Update(OverlayAddr) OverlayAddr
    72  }
    73  
    74  // Peer interface represents an live peer connection
    75  type Peer interface {
    76  	Addr                   // the address of a peer
    77  	Conn                   // the live connection (protocols.Peer)
    78  	LastActive() time.Time // last time active
    79  }
    80  
    81  // Conn interface represents an live peer connection
    82  type Conn interface {
    83  	ID() discover.NodeID                                                                  // the key that uniquely identifies the Node for the peerPool
    84  	Handshake(context.Context, interface{}, func(interface{}) error) (interface{}, error) // can send messages
    85  	Send(context.Context, interface{}) error                                              // can send messages
    86  	Drop(error)                                                                           // disconnect this peer
    87  	Run(func(context.Context, interface{}) error) error                                   // the run function to run a protocol
    88  	Off() OverlayAddr
    89  }
    90  
    91  // BzzConfig captures the config params used by the hive
    92  type BzzConfig struct {
    93  	OverlayAddr  []byte // base address of the overlay network
    94  	UnderlayAddr []byte // node's underlay address
    95  	HiveParams   *HiveParams
    96  	NetworkID    uint64
    97  	LightNode    bool
    98  }
    99  
   100  // Bzz is the swarm protocol bundle
   101  type Bzz struct {
   102  	*Hive
   103  	NetworkID    uint64
   104  	LightNode    bool
   105  	localAddr    *BzzAddr
   106  	mtx          sync.Mutex
   107  	handshakes   map[discover.NodeID]*HandshakeMsg
   108  	streamerSpec *protocols.Spec
   109  	streamerRun  func(*BzzPeer) error
   110  }
   111  
   112  // NewBzz is the swarm protocol constructor
   113  // arguments
   114  // * bzz config
   115  // * overlay driver
   116  // * peer store
   117  func NewBzz(config *BzzConfig, kad Overlay, store state.Store, streamerSpec *protocols.Spec, streamerRun func(*BzzPeer) error) *Bzz {
   118  	return &Bzz{
   119  		Hive:         NewHive(config.HiveParams, kad, store),
   120  		NetworkID:    config.NetworkID,
   121  		LightNode:    config.LightNode,
   122  		localAddr:    &BzzAddr{config.OverlayAddr, config.UnderlayAddr},
   123  		handshakes:   make(map[discover.NodeID]*HandshakeMsg),
   124  		streamerRun:  streamerRun,
   125  		streamerSpec: streamerSpec,
   126  	}
   127  }
   128  
   129  // UpdateLocalAddr updates underlayaddress of the running node
   130  func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *BzzAddr {
   131  	b.localAddr = b.localAddr.Update(&BzzAddr{
   132  		UAddr: byteaddr,
   133  		OAddr: b.localAddr.OAddr,
   134  	}).(*BzzAddr)
   135  	return b.localAddr
   136  }
   137  
   138  // NodeInfo returns the node's overlay address
   139  func (b *Bzz) NodeInfo() interface{} {
   140  	return b.localAddr.Address()
   141  }
   142  
   143  // Protocols return the protocols swarm offers
   144  // Bzz implements the node.Service interface
   145  // * handshake/hive
   146  // * discovery
   147  func (b *Bzz) Protocols() []p2p.Protocol {
   148  	protocol := []p2p.Protocol{
   149  		{
   150  			Name:     BzzSpec.Name,
   151  			Version:  BzzSpec.Version,
   152  			Length:   BzzSpec.Length(),
   153  			Run:      b.runBzz,
   154  			NodeInfo: b.NodeInfo,
   155  		},
   156  		{
   157  			Name:     DiscoverySpec.Name,
   158  			Version:  DiscoverySpec.Version,
   159  			Length:   DiscoverySpec.Length(),
   160  			Run:      b.RunProtocol(DiscoverySpec, b.Hive.Run),
   161  			NodeInfo: b.Hive.NodeInfo,
   162  			PeerInfo: b.Hive.PeerInfo,
   163  		},
   164  	}
   165  	if b.streamerSpec != nil && b.streamerRun != nil {
   166  		protocol = append(protocol, p2p.Protocol{
   167  			Name:    b.streamerSpec.Name,
   168  			Version: b.streamerSpec.Version,
   169  			Length:  b.streamerSpec.Length(),
   170  			Run:     b.RunProtocol(b.streamerSpec, b.streamerRun),
   171  		})
   172  	}
   173  	return protocol
   174  }
   175  
   176  // APIs returns the APIs offered by bzz
   177  // * hive
   178  // Bzz implements the node.Service interface
   179  func (b *Bzz) APIs() []rpc.API {
   180  	return []rpc.API{{
   181  		Namespace: "hive",
   182  		Version:   "3.0",
   183  		Service:   b.Hive,
   184  	}}
   185  }
   186  
   187  // RunProtocol is a wrapper for swarm subprotocols
   188  // returns a p2p protocol run function that can be assigned to p2p.Protocol#Run field
   189  // arguments:
   190  // * p2p protocol spec
   191  // * run function taking BzzPeer as argument
   192  //   this run function is meant to block for the duration of the protocol session
   193  //   on return the session is terminated and the peer is disconnected
   194  // the protocol waits for the bzz handshake is negotiated
   195  // the overlay address on the BzzPeer is set from the remote handshake
   196  func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(*p2p.Peer, p2p.MsgReadWriter) error {
   197  	return func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
   198  		// wait for the bzz protocol to perform the handshake
   199  		handshake, _ := b.GetHandshake(p.ID())
   200  		defer b.removeHandshake(p.ID())
   201  		select {
   202  		case <-handshake.done:
   203  		case <-time.After(bzzHandshakeTimeout):
   204  			return fmt.Errorf("%08x: %s protocol timeout waiting for handshake on %08x", b.BaseAddr()[:4], spec.Name, p.ID().Bytes()[:4])
   205  		}
   206  		if handshake.err != nil {
   207  			return fmt.Errorf("%08x: %s protocol closed: %v", b.BaseAddr()[:4], spec.Name, handshake.err)
   208  		}
   209  		// the handshake has succeeded so construct the BzzPeer and run the protocol
   210  		peer := &BzzPeer{
   211  			Peer:       protocols.NewPeer(p, rw, spec),
   212  			localAddr:  b.localAddr,
   213  			BzzAddr:    handshake.peerAddr,
   214  			lastActive: time.Now(),
   215  			LightNode:  handshake.LightNode,
   216  		}
   217  
   218  		log.Debug("peer created", "addr", handshake.peerAddr.String())
   219  
   220  		return run(peer)
   221  	}
   222  }
   223  
   224  // performHandshake implements the negotiation of the bzz handshake
   225  // shared among swarm subprotocols
   226  func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error {
   227  	ctx, cancel := context.WithTimeout(context.Background(), bzzHandshakeTimeout)
   228  	defer func() {
   229  		close(handshake.done)
   230  		cancel()
   231  	}()
   232  	rsh, err := p.Handshake(ctx, handshake, b.checkHandshake)
   233  	if err != nil {
   234  		handshake.err = err
   235  		return err
   236  	}
   237  	handshake.peerAddr = rsh.(*HandshakeMsg).Addr
   238  	handshake.LightNode = rsh.(*HandshakeMsg).LightNode
   239  	return nil
   240  }
   241  
   242  // runBzz is the p2p protocol run function for the bzz base protocol
   243  // that negotiates the bzz handshake
   244  func (b *Bzz) runBzz(p *p2p.Peer, rw p2p.MsgReadWriter) error {
   245  	handshake, _ := b.GetHandshake(p.ID())
   246  	if !<-handshake.init {
   247  		return fmt.Errorf("%08x: bzz already started on peer %08x", b.localAddr.Over()[:4], ToOverlayAddr(p.ID().Bytes())[:4])
   248  	}
   249  	close(handshake.init)
   250  	defer b.removeHandshake(p.ID())
   251  	peer := protocols.NewPeer(p, rw, BzzSpec)
   252  	err := b.performHandshake(peer, handshake)
   253  	if err != nil {
   254  		log.Warn(fmt.Sprintf("%08x: handshake failed with remote peer %08x: %v", b.localAddr.Over()[:4], ToOverlayAddr(p.ID().Bytes())[:4], err))
   255  
   256  		return err
   257  	}
   258  	// fail if we get another handshake
   259  	msg, err := rw.ReadMsg()
   260  	if err != nil {
   261  		return err
   262  	}
   263  	msg.Discard()
   264  	return errors.New("received multiple handshakes")
   265  }
   266  
   267  // BzzPeer is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer)
   268  // implements the Peer interface and all interfaces Peer implements: Addr, OverlayPeer
   269  type BzzPeer struct {
   270  	*protocols.Peer           // represents the connection for online peers
   271  	localAddr       *BzzAddr  // local Peers address
   272  	*BzzAddr                  // remote address -> implements Addr interface = protocols.Peer
   273  	lastActive      time.Time // time is updated whenever mutexes are releasing
   274  	LightNode       bool
   275  }
   276  
   277  func NewBzzTestPeer(p *protocols.Peer, addr *BzzAddr) *BzzPeer {
   278  	return &BzzPeer{
   279  		Peer:      p,
   280  		localAddr: addr,
   281  		BzzAddr:   NewAddrFromNodeID(p.ID()),
   282  	}
   283  }
   284  
   285  // Off returns the overlay peer record for offline persistence
   286  func (p *BzzPeer) Off() OverlayAddr {
   287  	return p.BzzAddr
   288  }
   289  
   290  // LastActive returns the time the peer was last active
   291  func (p *BzzPeer) LastActive() time.Time {
   292  	return p.lastActive
   293  }
   294  
   295  /*
   296   Handshake
   297  
   298  * Version: 8 byte integer version of the protocol
   299  * NetworkID: 8 byte integer network identifier
   300  * Addr: the address advertised by the node including underlay and overlay connecctions
   301  */
   302  type HandshakeMsg struct {
   303  	Version   uint64
   304  	NetworkID uint64
   305  	Addr      *BzzAddr
   306  	LightNode bool
   307  
   308  	// peerAddr is the address received in the peer handshake
   309  	peerAddr *BzzAddr
   310  
   311  	init chan bool
   312  	done chan struct{}
   313  	err  error
   314  }
   315  
   316  // String pretty prints the handshake
   317  func (bh *HandshakeMsg) String() string {
   318  	return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, LightNode: %v, peerAddr: %v", bh.Version, bh.NetworkID, bh.Addr, bh.LightNode, bh.peerAddr)
   319  }
   320  
   321  // Perform initiates the handshake and validates the remote handshake message
   322  func (b *Bzz) checkHandshake(hs interface{}) error {
   323  	rhs := hs.(*HandshakeMsg)
   324  	if rhs.NetworkID != b.NetworkID {
   325  		return fmt.Errorf("network id mismatch %d (!= %d)", rhs.NetworkID, b.NetworkID)
   326  	}
   327  	if rhs.Version != uint64(BzzSpec.Version) {
   328  		return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, BzzSpec.Version)
   329  	}
   330  	return nil
   331  }
   332  
   333  // removeHandshake removes handshake for peer with peerID
   334  // from the bzz handshake store
   335  func (b *Bzz) removeHandshake(peerID discover.NodeID) {
   336  	b.mtx.Lock()
   337  	defer b.mtx.Unlock()
   338  	delete(b.handshakes, peerID)
   339  }
   340  
   341  // GetHandshake returns the bzz handhake that the remote peer with peerID sent
   342  func (b *Bzz) GetHandshake(peerID discover.NodeID) (*HandshakeMsg, bool) {
   343  	b.mtx.Lock()
   344  	defer b.mtx.Unlock()
   345  	handshake, found := b.handshakes[peerID]
   346  	if !found {
   347  		handshake = &HandshakeMsg{
   348  			Version:   uint64(BzzSpec.Version),
   349  			NetworkID: b.NetworkID,
   350  			Addr:      b.localAddr,
   351  			LightNode: b.LightNode,
   352  			init:      make(chan bool, 1),
   353  			done:      make(chan struct{}),
   354  		}
   355  		// when handhsake is first created for a remote peer
   356  		// it is initialised with the init
   357  		handshake.init <- true
   358  		b.handshakes[peerID] = handshake
   359  	}
   360  
   361  	return handshake, found
   362  }
   363  
   364  // BzzAddr implements the PeerAddr interface
   365  type BzzAddr struct {
   366  	OAddr []byte
   367  	UAddr []byte
   368  }
   369  
   370  // Address implements OverlayPeer interface to be used in Overlay
   371  func (a *BzzAddr) Address() []byte {
   372  	return a.OAddr
   373  }
   374  
   375  // Over returns the overlay address
   376  func (a *BzzAddr) Over() []byte {
   377  	return a.OAddr
   378  }
   379  
   380  // Under returns the underlay address
   381  func (a *BzzAddr) Under() []byte {
   382  	return a.UAddr
   383  }
   384  
   385  // ID returns the nodeID from the underlay enode address
   386  func (a *BzzAddr) ID() discover.NodeID {
   387  	return discover.MustParseNode(string(a.UAddr)).ID
   388  }
   389  
   390  // Update updates the underlay address of a peer record
   391  func (a *BzzAddr) Update(na OverlayAddr) OverlayAddr {
   392  	return &BzzAddr{a.OAddr, na.(Addr).Under()}
   393  }
   394  
   395  // String pretty prints the address
   396  func (a *BzzAddr) String() string {
   397  	return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr)
   398  }
   399  
   400  // RandomAddr is a utility method generating an address from a public key
   401  func RandomAddr() *BzzAddr {
   402  	key, err := crypto.GenerateKey()
   403  	if err != nil {
   404  		panic("unable to generate key")
   405  	}
   406  	pubkey := crypto.FromECDSAPub(&key.PublicKey)
   407  	var id discover.NodeID
   408  	copy(id[:], pubkey[1:])
   409  	return NewAddrFromNodeID(id)
   410  }
   411  
   412  // NewNodeIDFromAddr transforms the underlay address to an adapters.NodeID
   413  func NewNodeIDFromAddr(addr Addr) discover.NodeID {
   414  	log.Info(fmt.Sprintf("uaddr=%s", string(addr.Under())))
   415  	node := discover.MustParseNode(string(addr.Under()))
   416  	return node.ID
   417  }
   418  
   419  // NewAddrFromNodeID constucts a BzzAddr from a discover.NodeID
   420  // the overlay address is derived as the hash of the nodeID
   421  func NewAddrFromNodeID(id discover.NodeID) *BzzAddr {
   422  	return &BzzAddr{
   423  		OAddr: ToOverlayAddr(id.Bytes()),
   424  		UAddr: []byte(discover.NewNode(id, net.IP{127, 0, 0, 1}, 30303, 30303).String()),
   425  	}
   426  }
   427  
   428  // NewAddrFromNodeIDAndPort constucts a BzzAddr from a discover.NodeID and port uint16
   429  // the overlay address is derived as the hash of the nodeID
   430  func NewAddrFromNodeIDAndPort(id discover.NodeID, host net.IP, port uint16) *BzzAddr {
   431  	return &BzzAddr{
   432  		OAddr: ToOverlayAddr(id.Bytes()),
   433  		UAddr: []byte(discover.NewNode(id, host, port, port).String()),
   434  	}
   435  }
   436  
   437  // ToOverlayAddr creates an overlayaddress from a byte slice
   438  func ToOverlayAddr(id []byte) []byte {
   439  	return crypto.Keccak256(id)
   440  }