github.com/bloxroute-labs/bor@v0.1.4/les/handler.go (about)

     1  // Copyright 2016 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  	"encoding/binary"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"math/big"
    25  	"sync"
    26  	"sync/atomic"
    27  	"time"
    28  
    29  	"github.com/maticnetwork/bor/common"
    30  	"github.com/maticnetwork/bor/core"
    31  	"github.com/maticnetwork/bor/core/rawdb"
    32  	"github.com/maticnetwork/bor/core/state"
    33  	"github.com/maticnetwork/bor/core/types"
    34  	"github.com/maticnetwork/bor/eth/downloader"
    35  	"github.com/maticnetwork/bor/ethdb"
    36  	"github.com/maticnetwork/bor/event"
    37  	"github.com/maticnetwork/bor/light"
    38  	"github.com/maticnetwork/bor/log"
    39  	"github.com/maticnetwork/bor/p2p"
    40  	"github.com/maticnetwork/bor/p2p/discv5"
    41  	"github.com/maticnetwork/bor/params"
    42  	"github.com/maticnetwork/bor/rlp"
    43  	"github.com/maticnetwork/bor/trie"
    44  )
    45  
    46  var errTooManyInvalidRequest = errors.New("too many invalid requests made")
    47  
    48  const (
    49  	softResponseLimit = 2 * 1024 * 1024 // Target maximum size of returned blocks, headers or node data.
    50  	estHeaderRlpSize  = 500             // Approximate size of an RLP encoded block header
    51  
    52  	ethVersion = 63 // equivalent eth version for the downloader
    53  
    54  	MaxHeaderFetch           = 192 // Amount of block headers to be fetched per retrieval request
    55  	MaxBodyFetch             = 32  // Amount of block bodies to be fetched per retrieval request
    56  	MaxReceiptFetch          = 128 // Amount of transaction receipts to allow fetching per request
    57  	MaxCodeFetch             = 64  // Amount of contract codes to allow fetching per request
    58  	MaxProofsFetch           = 64  // Amount of merkle proofs to be fetched per retrieval request
    59  	MaxHelperTrieProofsFetch = 64  // Amount of merkle proofs to be fetched per retrieval request
    60  	MaxTxSend                = 64  // Amount of transactions to be send per request
    61  	MaxTxStatus              = 256 // Amount of transactions to queried per request
    62  
    63  	disableClientRemovePeer = false
    64  )
    65  
    66  func errResp(code errCode, format string, v ...interface{}) error {
    67  	return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
    68  }
    69  
    70  type BlockChain interface {
    71  	Config() *params.ChainConfig
    72  	HasHeader(hash common.Hash, number uint64) bool
    73  	GetHeader(hash common.Hash, number uint64) *types.Header
    74  	GetHeaderByHash(hash common.Hash) *types.Header
    75  	CurrentHeader() *types.Header
    76  	GetTd(hash common.Hash, number uint64) *big.Int
    77  	StateCache() state.Database
    78  	InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
    79  	Rollback(chain []common.Hash)
    80  	GetHeaderByNumber(number uint64) *types.Header
    81  	GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64)
    82  	Genesis() *types.Block
    83  	SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
    84  }
    85  
    86  type txPool interface {
    87  	AddRemotes(txs []*types.Transaction) []error
    88  	Status(hashes []common.Hash) []core.TxStatus
    89  }
    90  
    91  type ProtocolManager struct {
    92  	// Configs
    93  	chainConfig *params.ChainConfig
    94  	iConfig     *light.IndexerConfig
    95  
    96  	client    bool   // The indicator whether the node is light client
    97  	maxPeers  int    // The maximum number peers allowed to connect.
    98  	networkId uint64 // The identity of network.
    99  
   100  	txpool       txPool
   101  	txrelay      *lesTxRelay
   102  	blockchain   BlockChain
   103  	chainDb      ethdb.Database
   104  	odr          *LesOdr
   105  	server       *LesServer
   106  	serverPool   *serverPool
   107  	lesTopic     discv5.Topic
   108  	reqDist      *requestDistributor
   109  	retriever    *retrieveManager
   110  	servingQueue *servingQueue
   111  	downloader   *downloader.Downloader
   112  	fetcher      *lightFetcher
   113  	ulc          *ulc
   114  	peers        *peerSet
   115  	checkpoint   *params.TrustedCheckpoint
   116  	reg          *checkpointOracle // If reg == nil, it means the checkpoint registrar is not activated
   117  
   118  	// channels for fetcher, syncer, txsyncLoop
   119  	newPeerCh   chan *peer
   120  	quitSync    chan struct{}
   121  	noMorePeers chan struct{}
   122  
   123  	wg       *sync.WaitGroup
   124  	eventMux *event.TypeMux
   125  
   126  	// Callbacks
   127  	synced func() bool
   128  }
   129  
   130  // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
   131  // with the ethereum network.
   132  func NewProtocolManager(chainConfig *params.ChainConfig, checkpoint *params.TrustedCheckpoint, indexerConfig *light.IndexerConfig, ulcServers []string, ulcFraction int, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointOracle, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) {
   133  	// Create the protocol manager with the base fields
   134  	manager := &ProtocolManager{
   135  		client:      client,
   136  		eventMux:    mux,
   137  		blockchain:  blockchain,
   138  		chainConfig: chainConfig,
   139  		iConfig:     indexerConfig,
   140  		chainDb:     chainDb,
   141  		odr:         odr,
   142  		networkId:   networkId,
   143  		txpool:      txpool,
   144  		serverPool:  serverPool,
   145  		reg:         registrar,
   146  		peers:       peers,
   147  		newPeerCh:   make(chan *peer),
   148  		quitSync:    quitSync,
   149  		wg:          wg,
   150  		noMorePeers: make(chan struct{}),
   151  		checkpoint:  checkpoint,
   152  		synced:      synced,
   153  	}
   154  	if odr != nil {
   155  		manager.retriever = odr.retriever
   156  		manager.reqDist = odr.retriever.dist
   157  	}
   158  
   159  	if ulcServers != nil {
   160  		ulc, err := newULC(ulcServers, ulcFraction)
   161  		if err != nil {
   162  			log.Warn("Failed to initialize ultra light client", "err", err)
   163  		} else {
   164  			manager.ulc = ulc
   165  		}
   166  	}
   167  	removePeer := manager.removePeer
   168  	if disableClientRemovePeer {
   169  		removePeer = func(id string) {}
   170  	}
   171  	if client {
   172  		var checkpointNumber uint64
   173  		if checkpoint != nil {
   174  			checkpointNumber = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1
   175  		}
   176  		manager.downloader = downloader.New(checkpointNumber, chainDb, nil, manager.eventMux, nil, blockchain, removePeer)
   177  		manager.peers.notify((*downloaderPeerNotify)(manager))
   178  		manager.fetcher = newLightFetcher(manager)
   179  	}
   180  	return manager, nil
   181  }
   182  
   183  // removePeer initiates disconnection from a peer by removing it from the peer set
   184  func (pm *ProtocolManager) removePeer(id string) {
   185  	pm.peers.Unregister(id)
   186  }
   187  
   188  func (pm *ProtocolManager) Start(maxPeers int) {
   189  	pm.maxPeers = maxPeers
   190  	if pm.client {
   191  		go pm.syncer()
   192  	} else {
   193  		go func() {
   194  			for range pm.newPeerCh {
   195  			}
   196  		}()
   197  	}
   198  }
   199  
   200  func (pm *ProtocolManager) Stop() {
   201  	// Showing a log message. During download / process this could actually
   202  	// take between 5 to 10 seconds and therefor feedback is required.
   203  	log.Info("Stopping light Ethereum protocol")
   204  
   205  	// Quit the sync loop.
   206  	// After this send has completed, no new peers will be accepted.
   207  	pm.noMorePeers <- struct{}{}
   208  
   209  	close(pm.quitSync) // quits syncer, fetcher
   210  
   211  	if pm.servingQueue != nil {
   212  		pm.servingQueue.stop()
   213  	}
   214  
   215  	// Disconnect existing sessions.
   216  	// This also closes the gate for any new registrations on the peer set.
   217  	// sessions which are already established but not added to pm.peers yet
   218  	// will exit when they try to register.
   219  	pm.peers.Close()
   220  
   221  	// Wait for any process action
   222  	pm.wg.Wait()
   223  
   224  	log.Info("Light Ethereum protocol stopped")
   225  }
   226  
   227  // runPeer is the p2p protocol run function for the given version.
   228  func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error {
   229  	var entry *poolEntry
   230  	peer := pm.newPeer(int(version), pm.networkId, p, rw)
   231  	if pm.serverPool != nil {
   232  		entry = pm.serverPool.connect(peer, peer.Node())
   233  	}
   234  	peer.poolEntry = entry
   235  	select {
   236  	case pm.newPeerCh <- peer:
   237  		pm.wg.Add(1)
   238  		defer pm.wg.Done()
   239  		err := pm.handle(peer)
   240  		if entry != nil {
   241  			pm.serverPool.disconnect(entry)
   242  		}
   243  		return err
   244  	case <-pm.quitSync:
   245  		if entry != nil {
   246  			pm.serverPool.disconnect(entry)
   247  		}
   248  		return p2p.DiscQuitting
   249  	}
   250  }
   251  
   252  func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
   253  	var trusted bool
   254  	if pm.ulc != nil {
   255  		trusted = pm.ulc.trusted(p.ID())
   256  	}
   257  	return newPeer(pv, nv, trusted, p, newMeteredMsgWriter(rw))
   258  }
   259  
   260  // handle is the callback invoked to manage the life cycle of a les peer. When
   261  // this function terminates, the peer is disconnected.
   262  func (pm *ProtocolManager) handle(p *peer) error {
   263  	// Ignore maxPeers if this is a trusted peer
   264  	// In server mode we try to check into the client pool after handshake
   265  	if pm.client && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted {
   266  		clientRejectedMeter.Mark(1)
   267  		return p2p.DiscTooManyPeers
   268  	}
   269  	// Reject light clients if server is not synced.
   270  	if !pm.client && !pm.synced() {
   271  		clientRejectedMeter.Mark(1)
   272  		return p2p.DiscRequested
   273  	}
   274  	p.Log().Debug("Light Ethereum peer connected", "name", p.Name())
   275  
   276  	// Execute the LES handshake
   277  	var (
   278  		genesis = pm.blockchain.Genesis()
   279  		head    = pm.blockchain.CurrentHeader()
   280  		hash    = head.Hash()
   281  		number  = head.Number.Uint64()
   282  		td      = pm.blockchain.GetTd(hash, number)
   283  	)
   284  	if err := p.Handshake(td, hash, number, genesis.Hash(), pm.server); err != nil {
   285  		p.Log().Debug("Light Ethereum handshake failed", "err", err)
   286  		clientErrorMeter.Mark(1)
   287  		return err
   288  	}
   289  	if p.fcClient != nil {
   290  		defer p.fcClient.Disconnect()
   291  	}
   292  
   293  	if rw, ok := p.rw.(*meteredMsgReadWriter); ok {
   294  		rw.Init(p.version)
   295  	}
   296  
   297  	// Register the peer locally
   298  	if err := pm.peers.Register(p); err != nil {
   299  		clientErrorMeter.Mark(1)
   300  		p.Log().Error("Light Ethereum peer registration failed", "err", err)
   301  		return err
   302  	}
   303  	connectedAt := time.Now()
   304  	defer func() {
   305  		pm.removePeer(p.id)
   306  		connectionTimer.UpdateSince(connectedAt)
   307  	}()
   308  
   309  	// Register the peer in the downloader. If the downloader considers it banned, we disconnect
   310  	if pm.client {
   311  		p.lock.Lock()
   312  		head := p.headInfo
   313  		p.lock.Unlock()
   314  		if pm.fetcher != nil {
   315  			pm.fetcher.announce(p, head)
   316  		}
   317  
   318  		if p.poolEntry != nil {
   319  			pm.serverPool.registered(p.poolEntry)
   320  		}
   321  	}
   322  	// main loop. handle incoming messages.
   323  	for {
   324  		if err := pm.handleMsg(p); err != nil {
   325  			p.Log().Debug("Light Ethereum message handling failed", "err", err)
   326  			if p.fcServer != nil {
   327  				p.fcServer.DumpLogs()
   328  			}
   329  			return err
   330  		}
   331  	}
   332  }
   333  
   334  // handleMsg is invoked whenever an inbound message is received from a remote
   335  // peer. The remote connection is torn down upon returning any error.
   336  func (pm *ProtocolManager) handleMsg(p *peer) error {
   337  	select {
   338  	case err := <-p.errCh:
   339  		return err
   340  	default:
   341  	}
   342  	// Read the next message from the remote peer, and ensure it's fully consumed
   343  	msg, err := p.rw.ReadMsg()
   344  	if err != nil {
   345  		return err
   346  	}
   347  	p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size)
   348  
   349  	p.responseCount++
   350  	responseCount := p.responseCount
   351  	var (
   352  		maxCost uint64
   353  		task    *servingTask
   354  	)
   355  
   356  	accept := func(reqID, reqCnt, maxCnt uint64) bool {
   357  		inSizeCost := func() uint64 {
   358  			if pm.server.costTracker != nil {
   359  				return pm.server.costTracker.realCost(0, msg.Size, 0)
   360  			}
   361  			return 0
   362  		}
   363  		if p.isFrozen() || reqCnt == 0 || p.fcClient == nil || reqCnt > maxCnt {
   364  			p.fcClient.OneTimeCost(inSizeCost())
   365  			return false
   366  		}
   367  		maxCost = p.fcCosts.getMaxCost(msg.Code, reqCnt)
   368  		gf := float64(1)
   369  		if pm.server.costTracker != nil {
   370  			gf = pm.server.costTracker.globalFactor()
   371  			if gf < 0.001 {
   372  				p.Log().Error("Invalid global cost factor", "globalFactor", gf)
   373  				gf = 1
   374  			}
   375  		}
   376  		maxTime := uint64(float64(maxCost) / gf)
   377  
   378  		if accepted, bufShort, servingPriority := p.fcClient.AcceptRequest(reqID, responseCount, maxCost); !accepted {
   379  			p.freezeClient()
   380  			p.Log().Warn("Request came too early", "remaining", common.PrettyDuration(time.Duration(bufShort*1000000/p.fcParams.MinRecharge)))
   381  			p.fcClient.OneTimeCost(inSizeCost())
   382  			return false
   383  		} else {
   384  			task = pm.servingQueue.newTask(p, maxTime, servingPriority)
   385  		}
   386  		if task.start() {
   387  			return true
   388  		}
   389  		p.fcClient.RequestProcessed(reqID, responseCount, maxCost, inSizeCost())
   390  		return false
   391  	}
   392  
   393  	if msg.Size > ProtocolMaxMsgSize {
   394  		return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
   395  	}
   396  	defer msg.Discard()
   397  
   398  	var deliverMsg *Msg
   399  
   400  	sendResponse := func(reqID, amount uint64, reply *reply, servingTime uint64) {
   401  		p.responseLock.Lock()
   402  		defer p.responseLock.Unlock()
   403  
   404  		if p.isFrozen() {
   405  			amount = 0
   406  			reply = nil
   407  		}
   408  		var replySize uint32
   409  		if reply != nil {
   410  			replySize = reply.size()
   411  		}
   412  		var realCost uint64
   413  		if pm.server.costTracker != nil {
   414  			realCost = pm.server.costTracker.realCost(servingTime, msg.Size, replySize)
   415  			if amount != 0 {
   416  				pm.server.costTracker.updateStats(msg.Code, amount, servingTime, realCost)
   417  			}
   418  		} else {
   419  			realCost = maxCost
   420  		}
   421  		bv := p.fcClient.RequestProcessed(reqID, responseCount, maxCost, realCost)
   422  		if reply != nil {
   423  			p.queueSend(func() {
   424  				if err := reply.send(bv); err != nil {
   425  					select {
   426  					case p.errCh <- err:
   427  					default:
   428  					}
   429  				}
   430  			})
   431  		}
   432  	}
   433  
   434  	// Handle the message depending on its contents
   435  	switch msg.Code {
   436  	case StatusMsg:
   437  		p.Log().Trace("Received status message")
   438  		// Status messages should never arrive after the handshake
   439  		return errResp(ErrExtraStatusMsg, "uncontrolled status message")
   440  
   441  	// Block header query, collect the requested headers and reply
   442  	case AnnounceMsg:
   443  		p.Log().Trace("Received announce message")
   444  		var req announceData
   445  		if err := msg.Decode(&req); err != nil {
   446  			return errResp(ErrDecode, "%v: %v", msg, err)
   447  		}
   448  		if err := req.sanityCheck(); err != nil {
   449  			return err
   450  		}
   451  		update, size := req.Update.decode()
   452  		if p.rejectUpdate(size) {
   453  			return errResp(ErrRequestRejected, "")
   454  		}
   455  		p.updateFlowControl(update)
   456  
   457  		if req.Hash != (common.Hash{}) {
   458  			if p.announceType == announceTypeNone {
   459  				return errResp(ErrUnexpectedResponse, "")
   460  			}
   461  			if p.announceType == announceTypeSigned {
   462  				if err := req.checkSignature(p.ID(), update); err != nil {
   463  					p.Log().Trace("Invalid announcement signature", "err", err)
   464  					return err
   465  				}
   466  				p.Log().Trace("Valid announcement signature")
   467  			}
   468  
   469  			p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth)
   470  			if pm.fetcher != nil {
   471  				pm.fetcher.announce(p, &req)
   472  			}
   473  		}
   474  
   475  	case GetBlockHeadersMsg:
   476  		p.Log().Trace("Received block header request")
   477  		// Decode the complex header query
   478  		var req struct {
   479  			ReqID uint64
   480  			Query getBlockHeadersData
   481  		}
   482  		if err := msg.Decode(&req); err != nil {
   483  			return errResp(ErrDecode, "%v: %v", msg, err)
   484  		}
   485  
   486  		query := req.Query
   487  		if accept(req.ReqID, query.Amount, MaxHeaderFetch) {
   488  			go func() {
   489  				hashMode := query.Origin.Hash != (common.Hash{})
   490  				first := true
   491  				maxNonCanonical := uint64(100)
   492  
   493  				// Gather headers until the fetch or network limits is reached
   494  				var (
   495  					bytes   common.StorageSize
   496  					headers []*types.Header
   497  					unknown bool
   498  				)
   499  				for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit {
   500  					if !first && !task.waitOrStop() {
   501  						sendResponse(req.ReqID, 0, nil, task.servingTime)
   502  						return
   503  					}
   504  					// Retrieve the next header satisfying the query
   505  					var origin *types.Header
   506  					if hashMode {
   507  						if first {
   508  							origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
   509  							if origin != nil {
   510  								query.Origin.Number = origin.Number.Uint64()
   511  							}
   512  						} else {
   513  							origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
   514  						}
   515  					} else {
   516  						origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
   517  					}
   518  					if origin == nil {
   519  						atomic.AddUint32(&p.invalidCount, 1)
   520  						break
   521  					}
   522  					headers = append(headers, origin)
   523  					bytes += estHeaderRlpSize
   524  
   525  					// Advance to the next header of the query
   526  					switch {
   527  					case hashMode && query.Reverse:
   528  						// Hash based traversal towards the genesis block
   529  						ancestor := query.Skip + 1
   530  						if ancestor == 0 {
   531  							unknown = true
   532  						} else {
   533  							query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
   534  							unknown = (query.Origin.Hash == common.Hash{})
   535  						}
   536  					case hashMode && !query.Reverse:
   537  						// Hash based traversal towards the leaf block
   538  						var (
   539  							current = origin.Number.Uint64()
   540  							next    = current + query.Skip + 1
   541  						)
   542  						if next <= current {
   543  							infos, _ := json.MarshalIndent(p.Peer.Info(), "", "  ")
   544  							p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos)
   545  							unknown = true
   546  						} else {
   547  							if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
   548  								nextHash := header.Hash()
   549  								expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
   550  								if expOldHash == query.Origin.Hash {
   551  									query.Origin.Hash, query.Origin.Number = nextHash, next
   552  								} else {
   553  									unknown = true
   554  								}
   555  							} else {
   556  								unknown = true
   557  							}
   558  						}
   559  					case query.Reverse:
   560  						// Number based traversal towards the genesis block
   561  						if query.Origin.Number >= query.Skip+1 {
   562  							query.Origin.Number -= query.Skip + 1
   563  						} else {
   564  							unknown = true
   565  						}
   566  					case !query.Reverse:
   567  						// Number based traversal towards the leaf block
   568  						query.Origin.Number += query.Skip + 1
   569  					}
   570  					first = false
   571  				}
   572  				sendResponse(req.ReqID, query.Amount, p.ReplyBlockHeaders(req.ReqID, headers), task.done())
   573  			}()
   574  		}
   575  
   576  	case BlockHeadersMsg:
   577  		if pm.downloader == nil {
   578  			return errResp(ErrUnexpectedResponse, "")
   579  		}
   580  
   581  		p.Log().Trace("Received block header response message")
   582  		// A batch of headers arrived to one of our previous requests
   583  		var resp struct {
   584  			ReqID, BV uint64
   585  			Headers   []*types.Header
   586  		}
   587  		if err := msg.Decode(&resp); err != nil {
   588  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   589  		}
   590  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   591  		if pm.fetcher != nil && pm.fetcher.requestedID(resp.ReqID) {
   592  			pm.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers)
   593  		} else {
   594  			err := pm.downloader.DeliverHeaders(p.id, resp.Headers)
   595  			if err != nil {
   596  				log.Debug(fmt.Sprint(err))
   597  			}
   598  		}
   599  
   600  	case GetBlockBodiesMsg:
   601  		p.Log().Trace("Received block bodies request")
   602  		// Decode the retrieval message
   603  		var req struct {
   604  			ReqID  uint64
   605  			Hashes []common.Hash
   606  		}
   607  		if err := msg.Decode(&req); err != nil {
   608  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   609  		}
   610  		// Gather blocks until the fetch or network limits is reached
   611  		var (
   612  			bytes  int
   613  			bodies []rlp.RawValue
   614  		)
   615  		reqCnt := len(req.Hashes)
   616  		if accept(req.ReqID, uint64(reqCnt), MaxBodyFetch) {
   617  			go func() {
   618  				for i, hash := range req.Hashes {
   619  					if i != 0 && !task.waitOrStop() {
   620  						sendResponse(req.ReqID, 0, nil, task.servingTime)
   621  						return
   622  					}
   623  					// Retrieve the requested block body, stopping if enough was found
   624  					if bytes >= softResponseLimit {
   625  						break
   626  					}
   627  					number := rawdb.ReadHeaderNumber(pm.chainDb, hash)
   628  					if number == nil {
   629  						atomic.AddUint32(&p.invalidCount, 1)
   630  						continue
   631  					}
   632  					if data := rawdb.ReadBodyRLP(pm.chainDb, hash, *number); len(data) != 0 {
   633  						bodies = append(bodies, data)
   634  						bytes += len(data)
   635  					}
   636  				}
   637  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyBlockBodiesRLP(req.ReqID, bodies), task.done())
   638  			}()
   639  		}
   640  
   641  	case BlockBodiesMsg:
   642  		if pm.odr == nil {
   643  			return errResp(ErrUnexpectedResponse, "")
   644  		}
   645  
   646  		p.Log().Trace("Received block bodies response")
   647  		// A batch of block bodies arrived to one of our previous requests
   648  		var resp struct {
   649  			ReqID, BV uint64
   650  			Data      []*types.Body
   651  		}
   652  		if err := msg.Decode(&resp); err != nil {
   653  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   654  		}
   655  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   656  		deliverMsg = &Msg{
   657  			MsgType: MsgBlockBodies,
   658  			ReqID:   resp.ReqID,
   659  			Obj:     resp.Data,
   660  		}
   661  
   662  	case GetCodeMsg:
   663  		p.Log().Trace("Received code request")
   664  		// Decode the retrieval message
   665  		var req struct {
   666  			ReqID uint64
   667  			Reqs  []CodeReq
   668  		}
   669  		if err := msg.Decode(&req); err != nil {
   670  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   671  		}
   672  		// Gather state data until the fetch or network limits is reached
   673  		var (
   674  			bytes int
   675  			data  [][]byte
   676  		)
   677  		reqCnt := len(req.Reqs)
   678  		if accept(req.ReqID, uint64(reqCnt), MaxCodeFetch) {
   679  			go func() {
   680  				for i, request := range req.Reqs {
   681  					if i != 0 && !task.waitOrStop() {
   682  						sendResponse(req.ReqID, 0, nil, task.servingTime)
   683  						return
   684  					}
   685  					// Look up the root hash belonging to the request
   686  					number := rawdb.ReadHeaderNumber(pm.chainDb, request.BHash)
   687  					if number == nil {
   688  						p.Log().Warn("Failed to retrieve block num for code", "hash", request.BHash)
   689  						atomic.AddUint32(&p.invalidCount, 1)
   690  						continue
   691  					}
   692  					header := rawdb.ReadHeader(pm.chainDb, request.BHash, *number)
   693  					if header == nil {
   694  						p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", request.BHash)
   695  						continue
   696  					}
   697  					// Refuse to search stale state data in the database since looking for
   698  					// a non-exist key is kind of expensive.
   699  					local := pm.blockchain.CurrentHeader().Number.Uint64()
   700  					if !pm.server.archiveMode && header.Number.Uint64()+core.TriesInMemory <= local {
   701  						p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local)
   702  						atomic.AddUint32(&p.invalidCount, 1)
   703  						continue
   704  					}
   705  					triedb := pm.blockchain.StateCache().TrieDB()
   706  
   707  					account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(request.AccKey))
   708  					if err != nil {
   709  						p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err)
   710  						atomic.AddUint32(&p.invalidCount, 1)
   711  						continue
   712  					}
   713  					code, err := triedb.Node(common.BytesToHash(account.CodeHash))
   714  					if err != nil {
   715  						p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err)
   716  						continue
   717  					}
   718  					// Accumulate the code and abort if enough data was retrieved
   719  					data = append(data, code)
   720  					if bytes += len(code); bytes >= softResponseLimit {
   721  						break
   722  					}
   723  				}
   724  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done())
   725  			}()
   726  		}
   727  
   728  	case CodeMsg:
   729  		if pm.odr == nil {
   730  			return errResp(ErrUnexpectedResponse, "")
   731  		}
   732  
   733  		p.Log().Trace("Received code response")
   734  		// A batch of node state data arrived to one of our previous requests
   735  		var resp struct {
   736  			ReqID, BV uint64
   737  			Data      [][]byte
   738  		}
   739  		if err := msg.Decode(&resp); err != nil {
   740  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   741  		}
   742  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   743  		deliverMsg = &Msg{
   744  			MsgType: MsgCode,
   745  			ReqID:   resp.ReqID,
   746  			Obj:     resp.Data,
   747  		}
   748  
   749  	case GetReceiptsMsg:
   750  		p.Log().Trace("Received receipts request")
   751  		// Decode the retrieval message
   752  		var req struct {
   753  			ReqID  uint64
   754  			Hashes []common.Hash
   755  		}
   756  		if err := msg.Decode(&req); err != nil {
   757  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   758  		}
   759  		// Gather state data until the fetch or network limits is reached
   760  		var (
   761  			bytes    int
   762  			receipts []rlp.RawValue
   763  		)
   764  		reqCnt := len(req.Hashes)
   765  		if accept(req.ReqID, uint64(reqCnt), MaxReceiptFetch) {
   766  			go func() {
   767  				for i, hash := range req.Hashes {
   768  					if i != 0 && !task.waitOrStop() {
   769  						sendResponse(req.ReqID, 0, nil, task.servingTime)
   770  						return
   771  					}
   772  					if bytes >= softResponseLimit {
   773  						break
   774  					}
   775  					// Retrieve the requested block's receipts, skipping if unknown to us
   776  					var results types.Receipts
   777  					number := rawdb.ReadHeaderNumber(pm.chainDb, hash)
   778  					if number == nil {
   779  						atomic.AddUint32(&p.invalidCount, 1)
   780  						continue
   781  					}
   782  					results = rawdb.ReadRawReceipts(pm.chainDb, hash, *number)
   783  					if results == nil {
   784  						if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash {
   785  							continue
   786  						}
   787  					}
   788  					// If known, encode and queue for response packet
   789  					if encoded, err := rlp.EncodeToBytes(results); err != nil {
   790  						log.Error("Failed to encode receipt", "err", err)
   791  					} else {
   792  						receipts = append(receipts, encoded)
   793  						bytes += len(encoded)
   794  					}
   795  				}
   796  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyReceiptsRLP(req.ReqID, receipts), task.done())
   797  			}()
   798  		}
   799  
   800  	case ReceiptsMsg:
   801  		if pm.odr == nil {
   802  			return errResp(ErrUnexpectedResponse, "")
   803  		}
   804  
   805  		p.Log().Trace("Received receipts response")
   806  		// A batch of receipts arrived to one of our previous requests
   807  		var resp struct {
   808  			ReqID, BV uint64
   809  			Receipts  []types.Receipts
   810  		}
   811  		if err := msg.Decode(&resp); err != nil {
   812  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   813  		}
   814  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   815  		deliverMsg = &Msg{
   816  			MsgType: MsgReceipts,
   817  			ReqID:   resp.ReqID,
   818  			Obj:     resp.Receipts,
   819  		}
   820  
   821  	case GetProofsV2Msg:
   822  		p.Log().Trace("Received les/2 proofs request")
   823  		// Decode the retrieval message
   824  		var req struct {
   825  			ReqID uint64
   826  			Reqs  []ProofReq
   827  		}
   828  		if err := msg.Decode(&req); err != nil {
   829  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   830  		}
   831  		// Gather state data until the fetch or network limits is reached
   832  		var (
   833  			lastBHash common.Hash
   834  			root      common.Hash
   835  		)
   836  		reqCnt := len(req.Reqs)
   837  		if accept(req.ReqID, uint64(reqCnt), MaxProofsFetch) {
   838  			go func() {
   839  				nodes := light.NewNodeSet()
   840  
   841  				for i, request := range req.Reqs {
   842  					if i != 0 && !task.waitOrStop() {
   843  						sendResponse(req.ReqID, 0, nil, task.servingTime)
   844  						return
   845  					}
   846  					// Look up the root hash belonging to the request
   847  					var (
   848  						number *uint64
   849  						header *types.Header
   850  						trie   state.Trie
   851  					)
   852  					if request.BHash != lastBHash {
   853  						root, lastBHash = common.Hash{}, request.BHash
   854  
   855  						if number = rawdb.ReadHeaderNumber(pm.chainDb, request.BHash); number == nil {
   856  							p.Log().Warn("Failed to retrieve block num for proof", "hash", request.BHash)
   857  							atomic.AddUint32(&p.invalidCount, 1)
   858  							continue
   859  						}
   860  						if header = rawdb.ReadHeader(pm.chainDb, request.BHash, *number); header == nil {
   861  							p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", request.BHash)
   862  							continue
   863  						}
   864  						// Refuse to search stale state data in the database since looking for
   865  						// a non-exist key is kind of expensive.
   866  						local := pm.blockchain.CurrentHeader().Number.Uint64()
   867  						if !pm.server.archiveMode && header.Number.Uint64()+core.TriesInMemory <= local {
   868  							p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local)
   869  							atomic.AddUint32(&p.invalidCount, 1)
   870  							continue
   871  						}
   872  						root = header.Root
   873  					}
   874  					// If a header lookup failed (non existent), ignore subsequent requests for the same header
   875  					if root == (common.Hash{}) {
   876  						atomic.AddUint32(&p.invalidCount, 1)
   877  						continue
   878  					}
   879  					// Open the account or storage trie for the request
   880  					statedb := pm.blockchain.StateCache()
   881  
   882  					switch len(request.AccKey) {
   883  					case 0:
   884  						// No account key specified, open an account trie
   885  						trie, err = statedb.OpenTrie(root)
   886  						if trie == nil || err != nil {
   887  							p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err)
   888  							continue
   889  						}
   890  					default:
   891  						// Account key specified, open a storage trie
   892  						account, err := pm.getAccount(statedb.TrieDB(), root, common.BytesToHash(request.AccKey))
   893  						if err != nil {
   894  							p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err)
   895  							atomic.AddUint32(&p.invalidCount, 1)
   896  							continue
   897  						}
   898  						trie, err = statedb.OpenStorageTrie(common.BytesToHash(request.AccKey), account.Root)
   899  						if trie == nil || err != nil {
   900  							p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "root", account.Root, "err", err)
   901  							continue
   902  						}
   903  					}
   904  					// Prove the user's request from the account or stroage trie
   905  					if err := trie.Prove(request.Key, request.FromLevel, nodes); err != nil {
   906  						p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err)
   907  						continue
   908  					}
   909  					if nodes.DataSize() >= softResponseLimit {
   910  						break
   911  					}
   912  				}
   913  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done())
   914  			}()
   915  		}
   916  
   917  	case ProofsV2Msg:
   918  		if pm.odr == nil {
   919  			return errResp(ErrUnexpectedResponse, "")
   920  		}
   921  
   922  		p.Log().Trace("Received les/2 proofs response")
   923  		// A batch of merkle proofs arrived to one of our previous requests
   924  		var resp struct {
   925  			ReqID, BV uint64
   926  			Data      light.NodeList
   927  		}
   928  		if err := msg.Decode(&resp); err != nil {
   929  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   930  		}
   931  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
   932  		deliverMsg = &Msg{
   933  			MsgType: MsgProofsV2,
   934  			ReqID:   resp.ReqID,
   935  			Obj:     resp.Data,
   936  		}
   937  
   938  	case GetHelperTrieProofsMsg:
   939  		p.Log().Trace("Received helper trie proof request")
   940  		// Decode the retrieval message
   941  		var req struct {
   942  			ReqID uint64
   943  			Reqs  []HelperTrieReq
   944  		}
   945  		if err := msg.Decode(&req); err != nil {
   946  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   947  		}
   948  		// Gather state data until the fetch or network limits is reached
   949  		var (
   950  			auxBytes int
   951  			auxData  [][]byte
   952  		)
   953  		reqCnt := len(req.Reqs)
   954  		if accept(req.ReqID, uint64(reqCnt), MaxHelperTrieProofsFetch) {
   955  			go func() {
   956  
   957  				var (
   958  					lastIdx  uint64
   959  					lastType uint
   960  					root     common.Hash
   961  					auxTrie  *trie.Trie
   962  				)
   963  				nodes := light.NewNodeSet()
   964  				for i, request := range req.Reqs {
   965  					if i != 0 && !task.waitOrStop() {
   966  						sendResponse(req.ReqID, 0, nil, task.servingTime)
   967  						return
   968  					}
   969  					if auxTrie == nil || request.Type != lastType || request.TrieIdx != lastIdx {
   970  						auxTrie, lastType, lastIdx = nil, request.Type, request.TrieIdx
   971  
   972  						var prefix string
   973  						if root, prefix = pm.getHelperTrie(request.Type, request.TrieIdx); root != (common.Hash{}) {
   974  							auxTrie, _ = trie.New(root, trie.NewDatabase(rawdb.NewTable(pm.chainDb, prefix)))
   975  						}
   976  					}
   977  					if request.AuxReq == auxRoot {
   978  						var data []byte
   979  						if root != (common.Hash{}) {
   980  							data = root[:]
   981  						}
   982  						auxData = append(auxData, data)
   983  						auxBytes += len(data)
   984  					} else {
   985  						if auxTrie != nil {
   986  							auxTrie.Prove(request.Key, request.FromLevel, nodes)
   987  						}
   988  						if request.AuxReq != 0 {
   989  							data := pm.getHelperTrieAuxData(request)
   990  							auxData = append(auxData, data)
   991  							auxBytes += len(data)
   992  						}
   993  					}
   994  					if nodes.DataSize()+auxBytes >= softResponseLimit {
   995  						break
   996  					}
   997  				}
   998  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}), task.done())
   999  			}()
  1000  		}
  1001  
  1002  	case HelperTrieProofsMsg:
  1003  		if pm.odr == nil {
  1004  			return errResp(ErrUnexpectedResponse, "")
  1005  		}
  1006  
  1007  		p.Log().Trace("Received helper trie proof response")
  1008  		var resp struct {
  1009  			ReqID, BV uint64
  1010  			Data      HelperTrieResps
  1011  		}
  1012  		if err := msg.Decode(&resp); err != nil {
  1013  			return errResp(ErrDecode, "msg %v: %v", msg, err)
  1014  		}
  1015  
  1016  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
  1017  		deliverMsg = &Msg{
  1018  			MsgType: MsgHelperTrieProofs,
  1019  			ReqID:   resp.ReqID,
  1020  			Obj:     resp.Data,
  1021  		}
  1022  
  1023  	case SendTxV2Msg:
  1024  		if pm.txpool == nil {
  1025  			return errResp(ErrRequestRejected, "")
  1026  		}
  1027  		// Transactions arrived, parse all of them and deliver to the pool
  1028  		var req struct {
  1029  			ReqID uint64
  1030  			Txs   []*types.Transaction
  1031  		}
  1032  		if err := msg.Decode(&req); err != nil {
  1033  			return errResp(ErrDecode, "msg %v: %v", msg, err)
  1034  		}
  1035  		reqCnt := len(req.Txs)
  1036  		if accept(req.ReqID, uint64(reqCnt), MaxTxSend) {
  1037  			go func() {
  1038  				stats := make([]light.TxStatus, len(req.Txs))
  1039  				for i, tx := range req.Txs {
  1040  					if i != 0 && !task.waitOrStop() {
  1041  						sendResponse(req.ReqID, 0, nil, task.servingTime)
  1042  						return
  1043  					}
  1044  					hash := tx.Hash()
  1045  					stats[i] = pm.txStatus(hash)
  1046  					if stats[i].Status == core.TxStatusUnknown {
  1047  						if errs := pm.txpool.AddRemotes([]*types.Transaction{tx}); errs[0] != nil {
  1048  							stats[i].Error = errs[0].Error()
  1049  							continue
  1050  						}
  1051  						stats[i] = pm.txStatus(hash)
  1052  					}
  1053  				}
  1054  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done())
  1055  			}()
  1056  		}
  1057  
  1058  	case GetTxStatusMsg:
  1059  		if pm.txpool == nil {
  1060  			return errResp(ErrUnexpectedResponse, "")
  1061  		}
  1062  		// Transactions arrived, parse all of them and deliver to the pool
  1063  		var req struct {
  1064  			ReqID  uint64
  1065  			Hashes []common.Hash
  1066  		}
  1067  		if err := msg.Decode(&req); err != nil {
  1068  			return errResp(ErrDecode, "msg %v: %v", msg, err)
  1069  		}
  1070  		reqCnt := len(req.Hashes)
  1071  		if accept(req.ReqID, uint64(reqCnt), MaxTxStatus) {
  1072  			go func() {
  1073  				stats := make([]light.TxStatus, len(req.Hashes))
  1074  				for i, hash := range req.Hashes {
  1075  					if i != 0 && !task.waitOrStop() {
  1076  						sendResponse(req.ReqID, 0, nil, task.servingTime)
  1077  						return
  1078  					}
  1079  					stats[i] = pm.txStatus(hash)
  1080  				}
  1081  				sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done())
  1082  			}()
  1083  		}
  1084  
  1085  	case TxStatusMsg:
  1086  		if pm.odr == nil {
  1087  			return errResp(ErrUnexpectedResponse, "")
  1088  		}
  1089  
  1090  		p.Log().Trace("Received tx status response")
  1091  		var resp struct {
  1092  			ReqID, BV uint64
  1093  			Status    []light.TxStatus
  1094  		}
  1095  		if err := msg.Decode(&resp); err != nil {
  1096  			return errResp(ErrDecode, "msg %v: %v", msg, err)
  1097  		}
  1098  
  1099  		p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
  1100  
  1101  		p.Log().Trace("Received helper trie proof response")
  1102  		deliverMsg = &Msg{
  1103  			MsgType: MsgTxStatus,
  1104  			ReqID:   resp.ReqID,
  1105  			Obj:     resp.Status,
  1106  		}
  1107  
  1108  	case StopMsg:
  1109  		if pm.odr == nil {
  1110  			return errResp(ErrUnexpectedResponse, "")
  1111  		}
  1112  		p.freezeServer(true)
  1113  		pm.retriever.frozen(p)
  1114  		p.Log().Warn("Service stopped")
  1115  
  1116  	case ResumeMsg:
  1117  		if pm.odr == nil {
  1118  			return errResp(ErrUnexpectedResponse, "")
  1119  		}
  1120  		var bv uint64
  1121  		if err := msg.Decode(&bv); err != nil {
  1122  			return errResp(ErrDecode, "msg %v: %v", msg, err)
  1123  		}
  1124  		p.fcServer.ResumeFreeze(bv)
  1125  		p.freezeServer(false)
  1126  		p.Log().Warn("Service resumed")
  1127  
  1128  	default:
  1129  		p.Log().Trace("Received unknown message", "code", msg.Code)
  1130  		return errResp(ErrInvalidMsgCode, "%v", msg.Code)
  1131  	}
  1132  
  1133  	if deliverMsg != nil {
  1134  		err := pm.retriever.deliver(p, deliverMsg)
  1135  		if err != nil {
  1136  			p.responseErrors++
  1137  			if p.responseErrors > maxResponseErrors {
  1138  				return err
  1139  			}
  1140  		}
  1141  	}
  1142  	// If the client has made too much invalid request(e.g. request a non-exist data),
  1143  	// reject them to prevent SPAM attack.
  1144  	if atomic.LoadUint32(&p.invalidCount) > maxRequestErrors {
  1145  		return errTooManyInvalidRequest
  1146  	}
  1147  	return nil
  1148  }
  1149  
  1150  // getAccount retrieves an account from the state based at root.
  1151  func (pm *ProtocolManager) getAccount(triedb *trie.Database, root, hash common.Hash) (state.Account, error) {
  1152  	trie, err := trie.New(root, triedb)
  1153  	if err != nil {
  1154  		return state.Account{}, err
  1155  	}
  1156  	blob, err := trie.TryGet(hash[:])
  1157  	if err != nil {
  1158  		return state.Account{}, err
  1159  	}
  1160  	var account state.Account
  1161  	if err = rlp.DecodeBytes(blob, &account); err != nil {
  1162  		return state.Account{}, err
  1163  	}
  1164  	return account, nil
  1165  }
  1166  
  1167  // getHelperTrie returns the post-processed trie root for the given trie ID and section index
  1168  func (pm *ProtocolManager) getHelperTrie(id uint, idx uint64) (common.Hash, string) {
  1169  	switch id {
  1170  	case htCanonical:
  1171  		sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, (idx+1)*pm.iConfig.ChtSize-1)
  1172  		return light.GetChtRoot(pm.chainDb, idx, sectionHead), light.ChtTablePrefix
  1173  	case htBloomBits:
  1174  		sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, (idx+1)*pm.iConfig.BloomTrieSize-1)
  1175  		return light.GetBloomTrieRoot(pm.chainDb, idx, sectionHead), light.BloomTrieTablePrefix
  1176  	}
  1177  	return common.Hash{}, ""
  1178  }
  1179  
  1180  // getHelperTrieAuxData returns requested auxiliary data for the given HelperTrie request
  1181  func (pm *ProtocolManager) getHelperTrieAuxData(req HelperTrieReq) []byte {
  1182  	if req.Type == htCanonical && req.AuxReq == auxHeader && len(req.Key) == 8 {
  1183  		blockNum := binary.BigEndian.Uint64(req.Key)
  1184  		hash := rawdb.ReadCanonicalHash(pm.chainDb, blockNum)
  1185  		return rawdb.ReadHeaderRLP(pm.chainDb, hash, blockNum)
  1186  	}
  1187  	return nil
  1188  }
  1189  
  1190  func (pm *ProtocolManager) txStatus(hash common.Hash) light.TxStatus {
  1191  	var stat light.TxStatus
  1192  	stat.Status = pm.txpool.Status([]common.Hash{hash})[0]
  1193  	// If the transaction is unknown to the pool, try looking it up locally
  1194  	if stat.Status == core.TxStatusUnknown {
  1195  		if tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(pm.chainDb, hash); tx != nil {
  1196  			stat.Status = core.TxStatusIncluded
  1197  			stat.Lookup = &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex}
  1198  		}
  1199  	}
  1200  	return stat
  1201  }
  1202  
  1203  // downloaderPeerNotify implements peerSetNotify
  1204  type downloaderPeerNotify ProtocolManager
  1205  
  1206  type peerConnection struct {
  1207  	manager *ProtocolManager
  1208  	peer    *peer
  1209  }
  1210  
  1211  func (pc *peerConnection) Head() (common.Hash, *big.Int) {
  1212  	return pc.peer.HeadAndTd()
  1213  }
  1214  
  1215  func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error {
  1216  	reqID := genReqID()
  1217  	rq := &distReq{
  1218  		getCost: func(dp distPeer) uint64 {
  1219  			peer := dp.(*peer)
  1220  			return peer.GetRequestCost(GetBlockHeadersMsg, amount)
  1221  		},
  1222  		canSend: func(dp distPeer) bool {
  1223  			return dp.(*peer) == pc.peer
  1224  		},
  1225  		request: func(dp distPeer) func() {
  1226  			peer := dp.(*peer)
  1227  			cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
  1228  			peer.fcServer.QueuedRequest(reqID, cost)
  1229  			return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) }
  1230  		},
  1231  	}
  1232  	_, ok := <-pc.manager.reqDist.queue(rq)
  1233  	if !ok {
  1234  		return light.ErrNoPeers
  1235  	}
  1236  	return nil
  1237  }
  1238  
  1239  func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error {
  1240  	reqID := genReqID()
  1241  	rq := &distReq{
  1242  		getCost: func(dp distPeer) uint64 {
  1243  			peer := dp.(*peer)
  1244  			return peer.GetRequestCost(GetBlockHeadersMsg, amount)
  1245  		},
  1246  		canSend: func(dp distPeer) bool {
  1247  			return dp.(*peer) == pc.peer
  1248  		},
  1249  		request: func(dp distPeer) func() {
  1250  			peer := dp.(*peer)
  1251  			cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
  1252  			peer.fcServer.QueuedRequest(reqID, cost)
  1253  			return func() { peer.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) }
  1254  		},
  1255  	}
  1256  	_, ok := <-pc.manager.reqDist.queue(rq)
  1257  	if !ok {
  1258  		return light.ErrNoPeers
  1259  	}
  1260  	return nil
  1261  }
  1262  
  1263  func (d *downloaderPeerNotify) registerPeer(p *peer) {
  1264  	pm := (*ProtocolManager)(d)
  1265  	pc := &peerConnection{
  1266  		manager: pm,
  1267  		peer:    p,
  1268  	}
  1269  	pm.downloader.RegisterLightPeer(p.id, ethVersion, pc)
  1270  }
  1271  
  1272  func (d *downloaderPeerNotify) unregisterPeer(p *peer) {
  1273  	pm := (*ProtocolManager)(d)
  1274  	pm.downloader.UnregisterPeer(p.id)
  1275  }