github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/swarm/network/protocol.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package network
    13  
    14  /*
    15  bzz implements the swarm wire protocol [bzz] (sister of eth and shh)
    16  the protocol instance is launched on each peer by the network layer if the
    17  bzz protocol handler is registered on the p2p server.
    18  
    19  The bzz protocol component speaks the bzz protocol
    20  * handle the protocol handshake
    21  * register peers in the KΛÐΞMLIΛ table via the hive logistic manager
    22  * dispatch to hive for handling the DHT logic
    23  * encode and decode requests for storage and retrieval
    24  * handle sync protocol messages via the syncer
    25  * talks the SWAP payment protocol (swap accounting is done within NetStore)
    26  */
    27  
    28  import (
    29  	"errors"
    30  	"fmt"
    31  	"net"
    32  	"strconv"
    33  	"time"
    34  
    35  	"github.com/Sberex/go-sberex/contracts/chequebook"
    36  	"github.com/Sberex/go-sberex/log"
    37  	"github.com/Sberex/go-sberex/metrics"
    38  	"github.com/Sberex/go-sberex/p2p"
    39  	bzzswap "github.com/Sberex/go-sberex/swarm/services/swap"
    40  	"github.com/Sberex/go-sberex/swarm/services/swap/swap"
    41  	"github.com/Sberex/go-sberex/swarm/storage"
    42  )
    43  
    44  //metrics variables
    45  var (
    46  	storeRequestMsgCounter    = metrics.NewRegisteredCounter("network.protocol.msg.storerequest.count", nil)
    47  	retrieveRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.retrieverequest.count", nil)
    48  	peersMsgCounter           = metrics.NewRegisteredCounter("network.protocol.msg.peers.count", nil)
    49  	syncRequestMsgCounter     = metrics.NewRegisteredCounter("network.protocol.msg.syncrequest.count", nil)
    50  	unsyncedKeysMsgCounter    = metrics.NewRegisteredCounter("network.protocol.msg.unsyncedkeys.count", nil)
    51  	deliverRequestMsgCounter  = metrics.NewRegisteredCounter("network.protocol.msg.deliverrequest.count", nil)
    52  	paymentMsgCounter         = metrics.NewRegisteredCounter("network.protocol.msg.payment.count", nil)
    53  	invalidMsgCounter         = metrics.NewRegisteredCounter("network.protocol.msg.invalid.count", nil)
    54  	handleStatusMsgCounter    = metrics.NewRegisteredCounter("network.protocol.msg.handlestatus.count", nil)
    55  )
    56  
    57  const (
    58  	Version            = 0
    59  	ProtocolLength     = uint64(8)
    60  	ProtocolMaxMsgSize = 10 * 1024 * 1024
    61  	NetworkId          = 3
    62  )
    63  
    64  // bzz represents the swarm wire protocol
    65  // an instance is running on each peer
    66  type bzz struct {
    67  	storage    StorageHandler       // handler storage/retrieval related requests coming via the bzz wire protocol
    68  	hive       *Hive                // the logistic manager, peerPool, routing service and peer handler
    69  	dbAccess   *DbAccess            // access to db storage counter and iterator for syncing
    70  	requestDb  *storage.LDBDatabase // db to persist backlog of deliveries to aid syncing
    71  	remoteAddr *peerAddr            // remote peers address
    72  	peer       *p2p.Peer            // the p2p peer object
    73  	rw         p2p.MsgReadWriter    // messageReadWriter to send messages to
    74  	backend    chequebook.Backend
    75  	lastActive time.Time
    76  	NetworkId  uint64
    77  
    78  	swap        *swap.Swap          // swap instance for the peer connection
    79  	swapParams  *bzzswap.SwapParams // swap settings both local and remote
    80  	swapEnabled bool                // flag to enable SWAP (will be set via Caps in handshake)
    81  	syncEnabled bool                // flag to enable SYNC (will be set via Caps in handshake)
    82  	syncer      *syncer             // syncer instance for the peer connection
    83  	syncParams  *SyncParams         // syncer params
    84  	syncState   *syncState          // outgoing syncronisation state (contains reference to remote peers db counter)
    85  }
    86  
    87  // interface type for handler of storage/retrieval related requests coming
    88  // via the bzz wire protocol
    89  // messages: UnsyncedKeys, DeliveryRequest, StoreRequest, RetrieveRequest
    90  type StorageHandler interface {
    91  	HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error
    92  	HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error
    93  	HandleStoreRequestMsg(req *storeRequestMsgData, p *peer)
    94  	HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
    95  }
    96  
    97  /*
    98  main entrypoint, wrappers starting a server that will run the bzz protocol
    99  use this constructor to attach the protocol ("class") to server caps
   100  This is done by node.Node#Register(func(node.ServiceContext) (Service, error))
   101  Service implements Protocols() which is an array of protocol constructors
   102  at node startup the protocols are initialised
   103  the Dev p2p layer then calls Run(p *p2p.Peer, rw p2p.MsgReadWriter) error
   104  on each peer connection
   105  The Run function of the Bzz protocol class creates a bzz instance
   106  which will represent the peer for the swarm hive and all peer-aware components
   107  */
   108  func Bzz(cloud StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64) (p2p.Protocol, error) {
   109  
   110  	// a single global request db is created for all peer connections
   111  	// this is to persist delivery backlog and aid syncronisation
   112  	requestDb, err := storage.NewLDBDatabase(sy.RequestDbPath)
   113  	if err != nil {
   114  		return p2p.Protocol{}, fmt.Errorf("error setting up request db: %v", err)
   115  	}
   116  	if networkId == 0 {
   117  		networkId = NetworkId
   118  	}
   119  	return p2p.Protocol{
   120  		Name:    "bzz",
   121  		Version: Version,
   122  		Length:  ProtocolLength,
   123  		Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
   124  			return run(requestDb, cloud, backend, hive, dbaccess, sp, sy, networkId, p, rw)
   125  		},
   126  	}, nil
   127  }
   128  
   129  /*
   130  the main protocol loop that
   131   * does the handshake by exchanging statusMsg
   132   * if peer is valid and accepted, registers with the hive
   133   * then enters into a forever loop handling incoming messages
   134   * storage and retrieval related queries coming via bzz are dispatched to StorageHandler
   135   * peer-related messages are dispatched to the hive
   136   * payment related messages are relayed to SWAP service
   137   * on disconnect, unregister the peer in the hive (note RemovePeer in the post-disconnect hook)
   138   * whenever the loop terminates, the peer will disconnect with Subprotocol error
   139   * whenever handlers return an error the loop terminates
   140  */
   141  func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64, p *p2p.Peer, rw p2p.MsgReadWriter) (err error) {
   142  
   143  	self := &bzz{
   144  		storage:     depo,
   145  		backend:     backend,
   146  		hive:        hive,
   147  		dbAccess:    dbaccess,
   148  		requestDb:   requestDb,
   149  		peer:        p,
   150  		rw:          rw,
   151  		swapParams:  sp,
   152  		syncParams:  sy,
   153  		swapEnabled: hive.swapEnabled,
   154  		syncEnabled: true,
   155  		NetworkId:   networkId,
   156  	}
   157  
   158  	// handle handshake
   159  	err = self.handleStatus()
   160  	if err != nil {
   161  		return err
   162  	}
   163  	defer func() {
   164  		// if the handler loop exits, the peer is disconnecting
   165  		// deregister the peer in the hive
   166  		self.hive.removePeer(&peer{bzz: self})
   167  		if self.syncer != nil {
   168  			self.syncer.stop() // quits request db and delivery loops, save requests
   169  		}
   170  		if self.swap != nil {
   171  			self.swap.Stop() // quits chequebox autocash etc
   172  		}
   173  	}()
   174  
   175  	// the main forever loop that handles incoming requests
   176  	for {
   177  		if self.hive.blockRead {
   178  			log.Warn(fmt.Sprintf("Cannot read network"))
   179  			time.Sleep(100 * time.Millisecond)
   180  			continue
   181  		}
   182  		err = self.handle()
   183  		if err != nil {
   184  			return
   185  		}
   186  	}
   187  }
   188  
   189  // TODO: may need to implement protocol drop only? don't want to kick off the peer
   190  // if they are useful for other protocols
   191  func (self *bzz) Drop() {
   192  	self.peer.Disconnect(p2p.DiscSubprotocolError)
   193  }
   194  
   195  // one cycle of the main forever loop that handles and dispatches incoming messages
   196  func (self *bzz) handle() error {
   197  	msg, err := self.rw.ReadMsg()
   198  	log.Debug(fmt.Sprintf("<- %v", msg))
   199  	if err != nil {
   200  		return err
   201  	}
   202  	if msg.Size > ProtocolMaxMsgSize {
   203  		return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize)
   204  	}
   205  	// make sure that the payload has been fully consumed
   206  	defer msg.Discard()
   207  
   208  	switch msg.Code {
   209  
   210  	case statusMsg:
   211  		// no extra status message allowed. The one needed already handled by
   212  		// handleStatus
   213  		log.Debug(fmt.Sprintf("Status message: %v", msg))
   214  		return errors.New("extra status message")
   215  
   216  	case storeRequestMsg:
   217  		// store requests are dispatched to netStore
   218  		storeRequestMsgCounter.Inc(1)
   219  		var req storeRequestMsgData
   220  		if err := msg.Decode(&req); err != nil {
   221  			return fmt.Errorf("<- %v: %v", msg, err)
   222  		}
   223  		if n := len(req.SData); n < 9 {
   224  			return fmt.Errorf("<- %v: Data too short (%v)", msg, n)
   225  		}
   226  		// last Active time is set only when receiving chunks
   227  		self.lastActive = time.Now()
   228  		log.Trace(fmt.Sprintf("incoming store request: %s", req.String()))
   229  		// swap accounting is done within forwarding
   230  		self.storage.HandleStoreRequestMsg(&req, &peer{bzz: self})
   231  
   232  	case retrieveRequestMsg:
   233  		// retrieve Requests are dispatched to netStore
   234  		retrieveRequestMsgCounter.Inc(1)
   235  		var req retrieveRequestMsgData
   236  		if err := msg.Decode(&req); err != nil {
   237  			return fmt.Errorf("<- %v: %v", msg, err)
   238  		}
   239  		req.from = &peer{bzz: self}
   240  		// if request is lookup and not to be delivered
   241  		if req.isLookup() {
   242  			log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from))
   243  		} else if req.Key == nil {
   244  			return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil")
   245  		} else {
   246  			// swap accounting is done within netStore
   247  			self.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: self})
   248  		}
   249  		// direct response with peers, TODO: sort this out
   250  		self.hive.peers(&req)
   251  
   252  	case peersMsg:
   253  		// response to lookups and immediate response to retrieve requests
   254  		// dispatches new peer data to the hive that adds them to KADDB
   255  		peersMsgCounter.Inc(1)
   256  		var req peersMsgData
   257  		if err := msg.Decode(&req); err != nil {
   258  			return fmt.Errorf("<- %v: %v", msg, err)
   259  		}
   260  		req.from = &peer{bzz: self}
   261  		log.Trace(fmt.Sprintf("<- peer addresses: %v", req))
   262  		self.hive.HandlePeersMsg(&req, &peer{bzz: self})
   263  
   264  	case syncRequestMsg:
   265  		syncRequestMsgCounter.Inc(1)
   266  		var req syncRequestMsgData
   267  		if err := msg.Decode(&req); err != nil {
   268  			return fmt.Errorf("<- %v: %v", msg, err)
   269  		}
   270  		log.Debug(fmt.Sprintf("<- sync request: %v", req))
   271  		self.lastActive = time.Now()
   272  		self.sync(req.SyncState)
   273  
   274  	case unsyncedKeysMsg:
   275  		// coming from parent node offering
   276  		unsyncedKeysMsgCounter.Inc(1)
   277  		var req unsyncedKeysMsgData
   278  		if err := msg.Decode(&req); err != nil {
   279  			return fmt.Errorf("<- %v: %v", msg, err)
   280  		}
   281  		log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String()))
   282  		err := self.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: self})
   283  		self.lastActive = time.Now()
   284  		if err != nil {
   285  			return fmt.Errorf("<- %v: %v", msg, err)
   286  		}
   287  
   288  	case deliveryRequestMsg:
   289  		// response to syncKeysMsg hashes filtered not existing in db
   290  		// also relays the last synced state to the source
   291  		deliverRequestMsgCounter.Inc(1)
   292  		var req deliveryRequestMsgData
   293  		if err := msg.Decode(&req); err != nil {
   294  			return fmt.Errorf("<-msg %v: %v", msg, err)
   295  		}
   296  		log.Debug(fmt.Sprintf("<- delivery request: %s", req.String()))
   297  		err := self.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: self})
   298  		self.lastActive = time.Now()
   299  		if err != nil {
   300  			return fmt.Errorf("<- %v: %v", msg, err)
   301  		}
   302  
   303  	case paymentMsg:
   304  		// swap protocol message for payment, Units paid for, Cheque paid with
   305  		paymentMsgCounter.Inc(1)
   306  		if self.swapEnabled {
   307  			var req paymentMsgData
   308  			if err := msg.Decode(&req); err != nil {
   309  				return fmt.Errorf("<- %v: %v", msg, err)
   310  			}
   311  			log.Debug(fmt.Sprintf("<- payment: %s", req.String()))
   312  			self.swap.Receive(int(req.Units), req.Promise)
   313  		}
   314  
   315  	default:
   316  		// no other message is allowed
   317  		invalidMsgCounter.Inc(1)
   318  		return fmt.Errorf("invalid message code: %v", msg.Code)
   319  	}
   320  	return nil
   321  }
   322  
   323  func (self *bzz) handleStatus() (err error) {
   324  
   325  	handshake := &statusMsgData{
   326  		Version:   uint64(Version),
   327  		ID:        "honey",
   328  		Addr:      self.selfAddr(),
   329  		NetworkId: self.NetworkId,
   330  		Swap: &bzzswap.SwapProfile{
   331  			Profile:    self.swapParams.Profile,
   332  			PayProfile: self.swapParams.PayProfile,
   333  		},
   334  	}
   335  
   336  	err = p2p.Send(self.rw, statusMsg, handshake)
   337  	if err != nil {
   338  		return err
   339  	}
   340  
   341  	// read and handle remote status
   342  	var msg p2p.Msg
   343  	msg, err = self.rw.ReadMsg()
   344  	if err != nil {
   345  		return err
   346  	}
   347  
   348  	if msg.Code != statusMsg {
   349  		return fmt.Errorf("first msg has code %x (!= %x)", msg.Code, statusMsg)
   350  	}
   351  
   352  	handleStatusMsgCounter.Inc(1)
   353  
   354  	if msg.Size > ProtocolMaxMsgSize {
   355  		return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize)
   356  	}
   357  
   358  	var status statusMsgData
   359  	if err := msg.Decode(&status); err != nil {
   360  		return fmt.Errorf("<- %v: %v", msg, err)
   361  	}
   362  
   363  	if status.NetworkId != self.NetworkId {
   364  		return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, self.NetworkId)
   365  	}
   366  
   367  	if Version != status.Version {
   368  		return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version)
   369  	}
   370  
   371  	self.remoteAddr = self.peerAddr(status.Addr)
   372  	log.Trace(fmt.Sprintf("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr()))
   373  
   374  	if self.swapEnabled {
   375  		// set remote profile for accounting
   376  		self.swap, err = bzzswap.NewSwap(self.swapParams, status.Swap, self.backend, self)
   377  		if err != nil {
   378  			return err
   379  		}
   380  	}
   381  
   382  	log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId))
   383  	err = self.hive.addPeer(&peer{bzz: self})
   384  	if err != nil {
   385  		return err
   386  	}
   387  
   388  	// hive sets syncstate so sync should start after node added
   389  	log.Info(fmt.Sprintf("syncronisation request sent with %v", self.syncState))
   390  	self.syncRequest()
   391  
   392  	return nil
   393  }
   394  
   395  func (self *bzz) sync(state *syncState) error {
   396  	// syncer setup
   397  	if self.syncer != nil {
   398  		return errors.New("sync request can only be sent once")
   399  	}
   400  
   401  	cnt := self.dbAccess.counter()
   402  	remoteaddr := self.remoteAddr.Addr
   403  	start, stop := self.hive.kad.KeyRange(remoteaddr)
   404  
   405  	// an explicitly received nil syncstate disables syncronisation
   406  	if state == nil {
   407  		self.syncEnabled = false
   408  		log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", self))
   409  		state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true}
   410  	} else {
   411  		state.synced = make(chan bool)
   412  		state.SessionAt = cnt
   413  		if storage.IsZeroKey(state.Stop) && state.Synced {
   414  			state.Start = storage.Key(start[:])
   415  			state.Stop = storage.Key(stop[:])
   416  		}
   417  		log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", self, state))
   418  	}
   419  	var err error
   420  	self.syncer, err = newSyncer(
   421  		self.requestDb,
   422  		storage.Key(remoteaddr[:]),
   423  		self.dbAccess,
   424  		self.unsyncedKeys, self.store,
   425  		self.syncParams, state, func() bool { return self.syncEnabled },
   426  	)
   427  	if err != nil {
   428  		return nil
   429  	}
   430  	log.Trace(fmt.Sprintf("syncer set for peer %v", self))
   431  	return nil
   432  }
   433  
   434  func (self *bzz) String() string {
   435  	return self.remoteAddr.String()
   436  }
   437  
   438  // repair reported address if IP missing
   439  func (self *bzz) peerAddr(base *peerAddr) *peerAddr {
   440  	if base.IP.IsUnspecified() {
   441  		host, _, _ := net.SplitHostPort(self.peer.RemoteAddr().String())
   442  		base.IP = net.ParseIP(host)
   443  	}
   444  	return base
   445  }
   446  
   447  // returns self advertised node connection info (listening address w enodes)
   448  // IP will get repaired on the other end if missing
   449  // or resolved via ID by discovery at dialout
   450  func (self *bzz) selfAddr() *peerAddr {
   451  	id := self.hive.id
   452  	host, port, _ := net.SplitHostPort(self.hive.listenAddr())
   453  	intport, _ := strconv.Atoi(port)
   454  	addr := &peerAddr{
   455  		Addr: self.hive.addr,
   456  		ID:   id[:],
   457  		IP:   net.ParseIP(host),
   458  		Port: uint16(intport),
   459  	}
   460  	return addr
   461  }
   462  
   463  // outgoing messages
   464  // send retrieveRequestMsg
   465  func (self *bzz) retrieve(req *retrieveRequestMsgData) error {
   466  	return self.send(retrieveRequestMsg, req)
   467  }
   468  
   469  // send storeRequestMsg
   470  func (self *bzz) store(req *storeRequestMsgData) error {
   471  	return self.send(storeRequestMsg, req)
   472  }
   473  
   474  func (self *bzz) syncRequest() error {
   475  	req := &syncRequestMsgData{}
   476  	if self.hive.syncEnabled {
   477  		log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", self, self.syncState))
   478  		req.SyncState = self.syncState
   479  	}
   480  	if self.syncState == nil {
   481  		log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", self, self.syncState))
   482  	}
   483  	return self.send(syncRequestMsg, req)
   484  }
   485  
   486  // queue storeRequestMsg in request db
   487  func (self *bzz) deliveryRequest(reqs []*syncRequest) error {
   488  	req := &deliveryRequestMsgData{
   489  		Deliver: reqs,
   490  	}
   491  	return self.send(deliveryRequestMsg, req)
   492  }
   493  
   494  // batch of syncRequests to send off
   495  func (self *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error {
   496  	req := &unsyncedKeysMsgData{
   497  		Unsynced: reqs,
   498  		State:    state,
   499  	}
   500  	return self.send(unsyncedKeysMsg, req)
   501  }
   502  
   503  // send paymentMsg
   504  func (self *bzz) Pay(units int, promise swap.Promise) {
   505  	req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)}
   506  	self.payment(req)
   507  }
   508  
   509  // send paymentMsg
   510  func (self *bzz) payment(req *paymentMsgData) error {
   511  	return self.send(paymentMsg, req)
   512  }
   513  
   514  // sends peersMsg
   515  func (self *bzz) peers(req *peersMsgData) error {
   516  	return self.send(peersMsg, req)
   517  }
   518  
   519  func (self *bzz) send(msg uint64, data interface{}) error {
   520  	if self.hive.blockWrite {
   521  		return fmt.Errorf("network write blocked")
   522  	}
   523  	log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, self))
   524  	err := p2p.Send(self.rw, msg, data)
   525  	if err != nil {
   526  		self.Drop()
   527  	}
   528  	return err
   529  }