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