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