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