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