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