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