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