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