github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/les/client_handler.go (about)

     1  // Copyright 2019 The ebakus/go-ebakus Authors
     2  // This file is part of the ebakus/go-ebakus library.
     3  //
     4  // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus 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/ebakus/go-ebakus/common"
    25  	"github.com/ebakus/go-ebakus/common/mclock"
    26  	"github.com/ebakus/go-ebakus/core/types"
    27  	"github.com/ebakus/go-ebakus/eth/downloader"
    28  	"github.com/ebakus/go-ebakus/light"
    29  	"github.com/ebakus/go-ebakus/log"
    30  	"github.com/ebakus/go-ebakus/p2p"
    31  	"github.com/ebakus/go-ebakus/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    *LightEbakus
    42  
    43  	closeCh  chan struct{}
    44  	wg       sync.WaitGroup // WaitGroup used to track all connected peers.
    45  	syncDone func()         // Test hooks when syncing is done.
    46  }
    47  
    48  func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEbakus) *clientHandler {
    49  	handler := &clientHandler{
    50  		checkpoint: checkpoint,
    51  		backend:    backend,
    52  		closeCh:    make(chan struct{}),
    53  	}
    54  	if ulcServers != nil {
    55  		ulc, err := newULC(ulcServers, ulcFraction)
    56  		if err != nil {
    57  			log.Error("Failed to initialize ultra light client")
    58  		}
    59  		handler.ulc = ulc
    60  		log.Info("Enable ultra light client mode")
    61  	}
    62  	var height uint64
    63  	if checkpoint != nil {
    64  		height = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1
    65  	}
    66  	handler.fetcher = newLightFetcher(handler)
    67  	handler.downloader = downloader.New(height, backend.chainDb, nil, backend.eventMux, nil, backend.blockchain, handler.removePeer)
    68  	handler.backend.peers.notify((*downloaderPeerNotify)(handler))
    69  	return handler
    70  }
    71  
    72  func (h *clientHandler) stop() {
    73  	close(h.closeCh)
    74  	h.downloader.Terminate()
    75  	h.fetcher.close()
    76  	h.wg.Wait()
    77  }
    78  
    79  // runPeer is the p2p protocol run function for the given version.
    80  func (h *clientHandler) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error {
    81  	trusted := false
    82  	if h.ulc != nil {
    83  		trusted = h.ulc.trusted(p.ID())
    84  	}
    85  	peer := newPeer(int(version), h.backend.config.NetworkId, trusted, p, newMeteredMsgWriter(rw, int(version)))
    86  	peer.poolEntry = h.backend.serverPool.connect(peer, peer.Node())
    87  	if peer.poolEntry == nil {
    88  		return p2p.DiscRequested
    89  	}
    90  	h.wg.Add(1)
    91  	defer h.wg.Done()
    92  	err := h.handle(peer)
    93  	h.backend.serverPool.disconnect(peer.poolEntry)
    94  	return err
    95  }
    96  
    97  func (h *clientHandler) handle(p *peer) error {
    98  	if h.backend.peers.Len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted {
    99  		return p2p.DiscTooManyPeers
   100  	}
   101  	p.Log().Debug("Light Ebakus peer connected", "name", p.Name())
   102  
   103  	// Execute the LES handshake
   104  	var (
   105  		head   = h.backend.blockchain.CurrentHeader()
   106  		hash   = head.Hash()
   107  		number = head.Number.Uint64()
   108  	)
   109  	if err := p.Handshake(big.NewInt(int64(number)), hash, number, h.backend.blockchain.Genesis().Hash(), nil); err != nil {
   110  		p.Log().Debug("Light Ebakus handshake failed", "err", err)
   111  		return err
   112  	}
   113  	// Register the peer locally
   114  	if err := h.backend.peers.Register(p); err != nil {
   115  		p.Log().Error("Light Ebakus peer registration failed", "err", err)
   116  		return err
   117  	}
   118  	serverConnectionGauge.Update(int64(h.backend.peers.Len()))
   119  
   120  	connectedAt := mclock.Now()
   121  	defer func() {
   122  		h.backend.peers.Unregister(p.id)
   123  		connectionTimer.Update(time.Duration(mclock.Now() - connectedAt))
   124  		serverConnectionGauge.Update(int64(h.backend.peers.Len()))
   125  	}()
   126  
   127  	h.fetcher.announce(p, p.headInfo)
   128  
   129  	// pool entry can be nil during the unit test.
   130  	if p.poolEntry != nil {
   131  		h.backend.serverPool.registered(p.poolEntry)
   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 Ebakus 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 *peer) 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 Ebakus 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 msg.Code {
   162  	case 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  
   177  		if req.Hash != (common.Hash{}) {
   178  			if p.announceType == announceTypeNone {
   179  				return errResp(ErrUnexpectedResponse, "")
   180  			}
   181  			if p.announceType == announceTypeSigned {
   182  				if err := req.checkSignature(p.ID(), update); err != nil {
   183  					p.Log().Trace("Invalid announcement signature", "err", err)
   184  					return err
   185  				}
   186  				p.Log().Trace("Valid announcement signature")
   187  			}
   188  			p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "reorg", req.ReorgDepth)
   189  			h.fetcher.announce(p, &req)
   190  		}
   191  	case BlockHeadersMsg:
   192  		p.Log().Trace("Received block header response message")
   193  		var resp struct {
   194  			ReqID, BV uint64
   195  			Headers   []*types.Header
   196  		}
   197  		if err := msg.Decode(&resp); err != nil {
   198  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   199  		}
   200  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   201  		if h.fetcher.requestedID(resp.ReqID) {
   202  			h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers)
   203  		} else {
   204  			if err := h.downloader.DeliverHeaders(p.id, resp.Headers); err != nil {
   205  				log.Debug("Failed to deliver headers", "err", err)
   206  			}
   207  		}
   208  	case BlockBodiesMsg:
   209  		p.Log().Trace("Received block bodies response")
   210  		var resp struct {
   211  			ReqID, BV uint64
   212  			Data      []*types.Body
   213  		}
   214  		if err := msg.Decode(&resp); err != nil {
   215  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   216  		}
   217  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   218  		deliverMsg = &Msg{
   219  			MsgType: MsgBlockBodies,
   220  			ReqID:   resp.ReqID,
   221  			Obj:     resp.Data,
   222  		}
   223  	case CodeMsg:
   224  		p.Log().Trace("Received code response")
   225  		var resp struct {
   226  			ReqID, BV uint64
   227  			Data      [][]byte
   228  		}
   229  		if err := msg.Decode(&resp); err != nil {
   230  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   231  		}
   232  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   233  		deliverMsg = &Msg{
   234  			MsgType: MsgCode,
   235  			ReqID:   resp.ReqID,
   236  			Obj:     resp.Data,
   237  		}
   238  	case ReceiptsMsg:
   239  		p.Log().Trace("Received receipts response")
   240  		var resp struct {
   241  			ReqID, BV uint64
   242  			Receipts  []types.Receipts
   243  		}
   244  		if err := msg.Decode(&resp); err != nil {
   245  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   246  		}
   247  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   248  		deliverMsg = &Msg{
   249  			MsgType: MsgReceipts,
   250  			ReqID:   resp.ReqID,
   251  			Obj:     resp.Receipts,
   252  		}
   253  	case ProofsV2Msg:
   254  		p.Log().Trace("Received les/2 proofs response")
   255  		var resp struct {
   256  			ReqID, BV uint64
   257  			Data      light.NodeList
   258  		}
   259  		if err := msg.Decode(&resp); err != nil {
   260  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   261  		}
   262  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   263  		deliverMsg = &Msg{
   264  			MsgType: MsgProofsV2,
   265  			ReqID:   resp.ReqID,
   266  			Obj:     resp.Data,
   267  		}
   268  	case HelperTrieProofsMsg:
   269  		p.Log().Trace("Received helper trie proof response")
   270  		var resp struct {
   271  			ReqID, BV uint64
   272  			Data      HelperTrieResps
   273  		}
   274  		if err := msg.Decode(&resp); err != nil {
   275  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   276  		}
   277  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   278  		deliverMsg = &Msg{
   279  			MsgType: MsgHelperTrieProofs,
   280  			ReqID:   resp.ReqID,
   281  			Obj:     resp.Data,
   282  		}
   283  	case TxStatusMsg:
   284  		p.Log().Trace("Received tx status response")
   285  		var resp struct {
   286  			ReqID, BV uint64
   287  			Status    []light.TxStatus
   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  		deliverMsg = &Msg{
   294  			MsgType: MsgTxStatus,
   295  			ReqID:   resp.ReqID,
   296  			Obj:     resp.Status,
   297  		}
   298  	case StopMsg:
   299  		p.freezeServer(true)
   300  		h.backend.retriever.frozen(p)
   301  		p.Log().Debug("Service stopped")
   302  	case ResumeMsg:
   303  		var bv uint64
   304  		if err := msg.Decode(&bv); err != nil {
   305  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   306  		}
   307  		p.fcServer.ResumeFreeze(bv)
   308  		p.freezeServer(false)
   309  		p.Log().Debug("Service resumed")
   310  	default:
   311  		p.Log().Trace("Received invalid message", "code", msg.Code)
   312  		return errResp(ErrInvalidMsgCode, "%v", msg.Code)
   313  	}
   314  	// Deliver the received response to retriever.
   315  	if deliverMsg != nil {
   316  		if err := h.backend.retriever.deliver(p, deliverMsg); err != nil {
   317  			p.responseErrors++
   318  			if p.responseErrors > maxResponseErrors {
   319  				return err
   320  			}
   321  		}
   322  	}
   323  	return nil
   324  }
   325  
   326  func (h *clientHandler) removePeer(id string) {
   327  	h.backend.peers.Unregister(id)
   328  }
   329  
   330  type peerConnection struct {
   331  	handler *clientHandler
   332  	peer    *peer
   333  }
   334  
   335  func (pc *peerConnection) Head() (common.Hash, *big.Int) {
   336  	return pc.peer.HeadAndTd()
   337  }
   338  
   339  func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error {
   340  	rq := &distReq{
   341  		getCost: func(dp distPeer) uint64 {
   342  			peer := dp.(*peer)
   343  			return peer.GetRequestCost(GetBlockHeadersMsg, amount)
   344  		},
   345  		canSend: func(dp distPeer) bool {
   346  			return dp.(*peer) == pc.peer
   347  		},
   348  		request: func(dp distPeer) func() {
   349  			reqID := genReqID()
   350  			peer := dp.(*peer)
   351  			cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
   352  			peer.fcServer.QueuedRequest(reqID, cost)
   353  			return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) }
   354  		},
   355  	}
   356  	_, ok := <-pc.handler.backend.reqDist.queue(rq)
   357  	if !ok {
   358  		return light.ErrNoPeers
   359  	}
   360  	return nil
   361  }
   362  
   363  func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error {
   364  	rq := &distReq{
   365  		getCost: func(dp distPeer) uint64 {
   366  			peer := dp.(*peer)
   367  			return peer.GetRequestCost(GetBlockHeadersMsg, amount)
   368  		},
   369  		canSend: func(dp distPeer) bool {
   370  			return dp.(*peer) == pc.peer
   371  		},
   372  		request: func(dp distPeer) func() {
   373  			reqID := genReqID()
   374  			peer := dp.(*peer)
   375  			cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
   376  			peer.fcServer.QueuedRequest(reqID, cost)
   377  			return func() { peer.RequestHeadersByNumber(reqID, cost, 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  // downloaderPeerNotify implements peerSetNotify
   388  type downloaderPeerNotify clientHandler
   389  
   390  func (d *downloaderPeerNotify) registerPeer(p *peer) {
   391  	h := (*clientHandler)(d)
   392  	pc := &peerConnection{
   393  		handler: h,
   394  		peer:    p,
   395  	}
   396  	h.downloader.RegisterLightPeer(p.id, ethVersion, pc)
   397  }
   398  
   399  func (d *downloaderPeerNotify) unregisterPeer(p *peer) {
   400  	h := (*clientHandler)(d)
   401  	h.downloader.UnregisterPeer(p.id)
   402  }