github.com/calmw/ethereum@v0.1.1/les/client_handler.go (about)

     1  // Copyright 2019 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 les
    18  
    19  import (
    20  	"context"
    21  	"math/big"
    22  	"math/rand"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/calmw/ethereum/common"
    27  	"github.com/calmw/ethereum/common/mclock"
    28  	"github.com/calmw/ethereum/core/forkid"
    29  	"github.com/calmw/ethereum/core/types"
    30  	"github.com/calmw/ethereum/eth/protocols/eth"
    31  	"github.com/calmw/ethereum/les/downloader"
    32  	"github.com/calmw/ethereum/light"
    33  	"github.com/calmw/ethereum/log"
    34  	"github.com/calmw/ethereum/p2p"
    35  )
    36  
    37  // clientHandler is responsible for receiving and processing all incoming server
    38  // responses.
    39  type clientHandler struct {
    40  	ulc        *ulc
    41  	forkFilter forkid.Filter
    42  	fetcher    *lightFetcher
    43  	downloader *downloader.Downloader
    44  	backend    *LightEthereum
    45  
    46  	closeCh chan struct{}
    47  	wg      sync.WaitGroup // WaitGroup used to track all connected peers.
    48  
    49  	// Hooks used in the testing
    50  	syncStart func(header *types.Header) // Hook called when the syncing is started
    51  	syncEnd   func(header *types.Header) // Hook called when the syncing is done
    52  }
    53  
    54  func newClientHandler(ulcServers []string, ulcFraction int, backend *LightEthereum) *clientHandler {
    55  	handler := &clientHandler{
    56  		forkFilter: forkid.NewFilter(backend.blockchain),
    57  		backend:    backend,
    58  		closeCh:    make(chan struct{}),
    59  	}
    60  	if ulcServers != nil {
    61  		ulc, err := newULC(ulcServers, ulcFraction)
    62  		if err != nil {
    63  			log.Error("Failed to initialize ultra light client")
    64  		}
    65  		handler.ulc = ulc
    66  		log.Info("Enable ultra light client mode")
    67  	}
    68  	handler.fetcher = newLightFetcher(backend.blockchain, backend.engine, backend.peers, handler.ulc, backend.chainDb, backend.reqDist, handler.synchronise)
    69  	handler.downloader = downloader.New(0, backend.chainDb, backend.eventMux, nil, backend.blockchain, handler.removePeer)
    70  	handler.backend.peers.subscribe((*downloaderPeerNotify)(handler))
    71  	return handler
    72  }
    73  
    74  func (h *clientHandler) start() {
    75  	h.fetcher.start()
    76  }
    77  
    78  func (h *clientHandler) stop() {
    79  	close(h.closeCh)
    80  	h.downloader.Terminate()
    81  	h.fetcher.stop()
    82  	h.wg.Wait()
    83  }
    84  
    85  // runPeer is the p2p protocol run function for the given version.
    86  func (h *clientHandler) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error {
    87  	trusted := false
    88  	if h.ulc != nil {
    89  		trusted = h.ulc.trusted(p.ID())
    90  	}
    91  	peer := newServerPeer(int(version), h.backend.config.NetworkId, trusted, p, newMeteredMsgWriter(rw, int(version)))
    92  	defer peer.close()
    93  	h.wg.Add(1)
    94  	defer h.wg.Done()
    95  	err := h.handle(peer, false)
    96  	return err
    97  }
    98  
    99  func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error {
   100  	if h.backend.peers.len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted {
   101  		return p2p.DiscTooManyPeers
   102  	}
   103  	p.Log().Debug("Light Ethereum peer connected", "name", p.Name())
   104  
   105  	// Execute the LES handshake
   106  	forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64(), h.backend.blockchain.CurrentHeader().Time)
   107  	if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil {
   108  		p.Log().Debug("Light Ethereum handshake failed", "err", err)
   109  		return err
   110  	}
   111  	// Register peer with the server pool
   112  	if h.backend.serverPool != nil {
   113  		if nvt, err := h.backend.serverPool.RegisterNode(p.Node()); err == nil {
   114  			p.setValueTracker(nvt)
   115  			p.updateVtParams()
   116  			defer func() {
   117  				p.setValueTracker(nil)
   118  				h.backend.serverPool.UnregisterNode(p.Node())
   119  			}()
   120  		} else {
   121  			return err
   122  		}
   123  	}
   124  	// Register the peer locally
   125  	if err := h.backend.peers.register(p); err != nil {
   126  		p.Log().Error("Light Ethereum peer registration failed", "err", err)
   127  		return err
   128  	}
   129  
   130  	serverConnectionGauge.Update(int64(h.backend.peers.len()))
   131  
   132  	connectedAt := mclock.Now()
   133  	defer func() {
   134  		h.backend.peers.unregister(p.id)
   135  		connectionTimer.Update(time.Duration(mclock.Now() - connectedAt))
   136  		serverConnectionGauge.Update(int64(h.backend.peers.len()))
   137  	}()
   138  
   139  	// Discard all the announces after the transition
   140  	// Also discarding initial signal to prevent syncing during testing.
   141  	if !(noInitAnnounce || h.backend.merger.TDDReached()) {
   142  		h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td})
   143  	}
   144  
   145  	// Mark the peer starts to be served.
   146  	p.serving.Store(true)
   147  	defer p.serving.Store(false)
   148  
   149  	// Spawn a main loop to handle all incoming messages.
   150  	for {
   151  		if err := h.handleMsg(p); err != nil {
   152  			p.Log().Debug("Light Ethereum message handling failed", "err", err)
   153  			p.fcServer.DumpLogs()
   154  			return err
   155  		}
   156  	}
   157  }
   158  
   159  // handleMsg is invoked whenever an inbound message is received from a remote
   160  // peer. The remote connection is torn down upon returning any error.
   161  func (h *clientHandler) handleMsg(p *serverPeer) error {
   162  	// Read the next message from the remote peer, and ensure it's fully consumed
   163  	msg, err := p.rw.ReadMsg()
   164  	if err != nil {
   165  		return err
   166  	}
   167  	p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size)
   168  
   169  	if msg.Size > ProtocolMaxMsgSize {
   170  		return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
   171  	}
   172  	defer msg.Discard()
   173  
   174  	var deliverMsg *Msg
   175  
   176  	// Handle the message depending on its contents
   177  	switch {
   178  	case msg.Code == AnnounceMsg:
   179  		p.Log().Trace("Received announce message")
   180  		var req announceData
   181  		if err := msg.Decode(&req); err != nil {
   182  			return errResp(ErrDecode, "%v: %v", msg, err)
   183  		}
   184  		if err := req.sanityCheck(); err != nil {
   185  			return err
   186  		}
   187  		update, size := req.Update.decode()
   188  		if p.rejectUpdate(size) {
   189  			return errResp(ErrRequestRejected, "")
   190  		}
   191  		p.updateFlowControl(update)
   192  		p.updateVtParams()
   193  
   194  		if req.Hash != (common.Hash{}) {
   195  			if p.announceType == announceTypeNone {
   196  				return errResp(ErrUnexpectedResponse, "")
   197  			}
   198  			if p.announceType == announceTypeSigned {
   199  				if err := req.checkSignature(p.ID(), update); err != nil {
   200  					p.Log().Trace("Invalid announcement signature", "err", err)
   201  					return err
   202  				}
   203  				p.Log().Trace("Valid announcement signature")
   204  			}
   205  			p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth)
   206  
   207  			// Update peer head information first and then notify the announcement
   208  			p.updateHead(req.Hash, req.Number, req.Td)
   209  
   210  			// Discard all the announces after the transition
   211  			if !h.backend.merger.TDDReached() {
   212  				h.fetcher.announce(p, &req)
   213  			}
   214  		}
   215  	case msg.Code == BlockHeadersMsg:
   216  		p.Log().Trace("Received block header response message")
   217  		var resp struct {
   218  			ReqID, BV uint64
   219  			Headers   []*types.Header
   220  		}
   221  		if err := msg.Decode(&resp); err != nil {
   222  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   223  		}
   224  		headers := resp.Headers
   225  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   226  		p.answeredRequest(resp.ReqID)
   227  
   228  		// Filter out the explicitly requested header by the retriever
   229  		if h.backend.retriever.requested(resp.ReqID) {
   230  			deliverMsg = &Msg{
   231  				MsgType: MsgBlockHeaders,
   232  				ReqID:   resp.ReqID,
   233  				Obj:     resp.Headers,
   234  			}
   235  		} else {
   236  			// Filter out any explicitly requested headers, deliver the rest to the downloader
   237  			filter := len(headers) == 1
   238  			if filter {
   239  				headers = h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers)
   240  			}
   241  			if len(headers) != 0 || !filter {
   242  				if err := h.downloader.DeliverHeaders(p.id, headers); err != nil {
   243  					log.Debug("Failed to deliver headers", "err", err)
   244  				}
   245  			}
   246  		}
   247  	case msg.Code == BlockBodiesMsg:
   248  		p.Log().Trace("Received block bodies response")
   249  		var resp struct {
   250  			ReqID, BV uint64
   251  			Data      []*types.Body
   252  		}
   253  		if err := msg.Decode(&resp); err != nil {
   254  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   255  		}
   256  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   257  		p.answeredRequest(resp.ReqID)
   258  		deliverMsg = &Msg{
   259  			MsgType: MsgBlockBodies,
   260  			ReqID:   resp.ReqID,
   261  			Obj:     resp.Data,
   262  		}
   263  	case msg.Code == CodeMsg:
   264  		p.Log().Trace("Received code response")
   265  		var resp struct {
   266  			ReqID, BV uint64
   267  			Data      [][]byte
   268  		}
   269  		if err := msg.Decode(&resp); err != nil {
   270  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   271  		}
   272  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   273  		p.answeredRequest(resp.ReqID)
   274  		deliverMsg = &Msg{
   275  			MsgType: MsgCode,
   276  			ReqID:   resp.ReqID,
   277  			Obj:     resp.Data,
   278  		}
   279  	case msg.Code == ReceiptsMsg:
   280  		p.Log().Trace("Received receipts response")
   281  		var resp struct {
   282  			ReqID, BV uint64
   283  			Receipts  []types.Receipts
   284  		}
   285  		if err := msg.Decode(&resp); err != nil {
   286  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   287  		}
   288  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   289  		p.answeredRequest(resp.ReqID)
   290  		deliverMsg = &Msg{
   291  			MsgType: MsgReceipts,
   292  			ReqID:   resp.ReqID,
   293  			Obj:     resp.Receipts,
   294  		}
   295  	case msg.Code == ProofsV2Msg:
   296  		p.Log().Trace("Received les/2 proofs response")
   297  		var resp struct {
   298  			ReqID, BV uint64
   299  			Data      light.NodeList
   300  		}
   301  		if err := msg.Decode(&resp); err != nil {
   302  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   303  		}
   304  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   305  		p.answeredRequest(resp.ReqID)
   306  		deliverMsg = &Msg{
   307  			MsgType: MsgProofsV2,
   308  			ReqID:   resp.ReqID,
   309  			Obj:     resp.Data,
   310  		}
   311  	case msg.Code == HelperTrieProofsMsg:
   312  		p.Log().Trace("Received helper trie proof response")
   313  		var resp struct {
   314  			ReqID, BV uint64
   315  			Data      HelperTrieResps
   316  		}
   317  		if err := msg.Decode(&resp); err != nil {
   318  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   319  		}
   320  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   321  		p.answeredRequest(resp.ReqID)
   322  		deliverMsg = &Msg{
   323  			MsgType: MsgHelperTrieProofs,
   324  			ReqID:   resp.ReqID,
   325  			Obj:     resp.Data,
   326  		}
   327  	case msg.Code == TxStatusMsg:
   328  		p.Log().Trace("Received tx status response")
   329  		var resp struct {
   330  			ReqID, BV uint64
   331  			Status    []light.TxStatus
   332  		}
   333  		if err := msg.Decode(&resp); err != nil {
   334  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   335  		}
   336  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   337  		p.answeredRequest(resp.ReqID)
   338  		deliverMsg = &Msg{
   339  			MsgType: MsgTxStatus,
   340  			ReqID:   resp.ReqID,
   341  			Obj:     resp.Status,
   342  		}
   343  	case msg.Code == StopMsg && p.version >= lpv3:
   344  		p.freeze()
   345  		h.backend.retriever.frozen(p)
   346  		p.Log().Debug("Service stopped")
   347  	case msg.Code == ResumeMsg && p.version >= lpv3:
   348  		var bv uint64
   349  		if err := msg.Decode(&bv); err != nil {
   350  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   351  		}
   352  		p.fcServer.ResumeFreeze(bv)
   353  		p.unfreeze()
   354  		p.Log().Debug("Service resumed")
   355  	default:
   356  		p.Log().Trace("Received invalid message", "code", msg.Code)
   357  		return errResp(ErrInvalidMsgCode, "%v", msg.Code)
   358  	}
   359  	// Deliver the received response to retriever.
   360  	if deliverMsg != nil {
   361  		if err := h.backend.retriever.deliver(p, deliverMsg); err != nil {
   362  			if val := p.errCount.Add(1, mclock.Now()); val > maxResponseErrors {
   363  				return err
   364  			}
   365  		}
   366  	}
   367  	return nil
   368  }
   369  
   370  func (h *clientHandler) removePeer(id string) {
   371  	h.backend.peers.unregister(id)
   372  }
   373  
   374  type peerConnection struct {
   375  	handler *clientHandler
   376  	peer    *serverPeer
   377  }
   378  
   379  func (pc *peerConnection) Head() (common.Hash, *big.Int) {
   380  	return pc.peer.HeadAndTd()
   381  }
   382  
   383  func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error {
   384  	rq := &distReq{
   385  		getCost: func(dp distPeer) uint64 {
   386  			peer := dp.(*serverPeer)
   387  			return peer.getRequestCost(GetBlockHeadersMsg, amount)
   388  		},
   389  		canSend: func(dp distPeer) bool {
   390  			return dp.(*serverPeer) == pc.peer
   391  		},
   392  		request: func(dp distPeer) func() {
   393  			reqID := rand.Uint64()
   394  			peer := dp.(*serverPeer)
   395  			cost := peer.getRequestCost(GetBlockHeadersMsg, amount)
   396  			peer.fcServer.QueuedRequest(reqID, cost)
   397  			return func() { peer.requestHeadersByHash(reqID, origin, amount, skip, reverse) }
   398  		},
   399  	}
   400  	_, ok := <-pc.handler.backend.reqDist.queue(rq)
   401  	if !ok {
   402  		return light.ErrNoPeers
   403  	}
   404  	return nil
   405  }
   406  
   407  func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error {
   408  	rq := &distReq{
   409  		getCost: func(dp distPeer) uint64 {
   410  			peer := dp.(*serverPeer)
   411  			return peer.getRequestCost(GetBlockHeadersMsg, amount)
   412  		},
   413  		canSend: func(dp distPeer) bool {
   414  			return dp.(*serverPeer) == pc.peer
   415  		},
   416  		request: func(dp distPeer) func() {
   417  			reqID := rand.Uint64()
   418  			peer := dp.(*serverPeer)
   419  			cost := peer.getRequestCost(GetBlockHeadersMsg, amount)
   420  			peer.fcServer.QueuedRequest(reqID, cost)
   421  			return func() { peer.requestHeadersByNumber(reqID, origin, amount, skip, reverse) }
   422  		},
   423  	}
   424  	_, ok := <-pc.handler.backend.reqDist.queue(rq)
   425  	if !ok {
   426  		return light.ErrNoPeers
   427  	}
   428  	return nil
   429  }
   430  
   431  // RetrieveSingleHeaderByNumber requests a single header by the specified block
   432  // number. This function will wait the response until it's timeout or delivered.
   433  func (pc *peerConnection) RetrieveSingleHeaderByNumber(context context.Context, number uint64) (*types.Header, error) {
   434  	reqID := rand.Uint64()
   435  	rq := &distReq{
   436  		getCost: func(dp distPeer) uint64 {
   437  			peer := dp.(*serverPeer)
   438  			return peer.getRequestCost(GetBlockHeadersMsg, 1)
   439  		},
   440  		canSend: func(dp distPeer) bool {
   441  			return dp.(*serverPeer) == pc.peer
   442  		},
   443  		request: func(dp distPeer) func() {
   444  			peer := dp.(*serverPeer)
   445  			cost := peer.getRequestCost(GetBlockHeadersMsg, 1)
   446  			peer.fcServer.QueuedRequest(reqID, cost)
   447  			return func() { peer.requestHeadersByNumber(reqID, number, 1, 0, false) }
   448  		},
   449  	}
   450  	var header *types.Header
   451  	if err := pc.handler.backend.retriever.retrieve(context, reqID, rq, func(peer distPeer, msg *Msg) error {
   452  		if msg.MsgType != MsgBlockHeaders {
   453  			return errInvalidMessageType
   454  		}
   455  		headers := msg.Obj.([]*types.Header)
   456  		if len(headers) != 1 {
   457  			return errInvalidEntryCount
   458  		}
   459  		header = headers[0]
   460  		return nil
   461  	}, nil); err != nil {
   462  		return nil, err
   463  	}
   464  	return header, nil
   465  }
   466  
   467  // downloaderPeerNotify implements peerSetNotify
   468  type downloaderPeerNotify clientHandler
   469  
   470  func (d *downloaderPeerNotify) registerPeer(p *serverPeer) {
   471  	h := (*clientHandler)(d)
   472  	pc := &peerConnection{
   473  		handler: h,
   474  		peer:    p,
   475  	}
   476  	h.downloader.RegisterLightPeer(p.id, eth.ETH66, pc)
   477  }
   478  
   479  func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) {
   480  	h := (*clientHandler)(d)
   481  	h.downloader.UnregisterPeer(p.id)
   482  }