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