github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/network/protocol.go (about)

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