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