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