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