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