github.com/core-coin/go-core/v2@v2.1.9/les/client_handler.go (about)

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