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