github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/les/handler.go (about)

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