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