github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/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/wanchain/go-wanchain/common" 30 "github.com/wanchain/go-wanchain/consensus" 31 "github.com/wanchain/go-wanchain/core" 32 "github.com/wanchain/go-wanchain/core/state" 33 "github.com/wanchain/go-wanchain/core/types" 34 "github.com/wanchain/go-wanchain/eth" 35 "github.com/wanchain/go-wanchain/eth/downloader" 36 "github.com/wanchain/go-wanchain/ethdb" 37 "github.com/wanchain/go-wanchain/event" 38 "github.com/wanchain/go-wanchain/log" 39 "github.com/wanchain/go-wanchain/p2p" 40 "github.com/wanchain/go-wanchain/p2p/discover" 41 "github.com/wanchain/go-wanchain/p2p/discv5" 42 "github.com/wanchain/go-wanchain/params" 43 "github.com/wanchain/go-wanchain/rlp" 44 "github.com/wanchain/go-wanchain/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 MaxHeaderProofsFetch = 64 // Amount of merkle proofs to be fetched per retrieval request 59 MaxTxSend = 64 // Amount of transactions to be send per request 60 61 disableClientRemovePeer = false 62 ) 63 64 // errIncompatibleConfig is returned if the requested protocols and configs are 65 // not compatible (low protocol version restrictions and high requirements). 66 var errIncompatibleConfig = errors.New("incompatible configuration") 67 68 func errResp(code errCode, format string, v ...interface{}) error { 69 return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...)) 70 } 71 72 type BlockChain interface { 73 HasHeader(hash common.Hash, number uint64) bool 74 GetHeader(hash common.Hash, number uint64) *types.Header 75 GetHeaderByHash(hash common.Hash) *types.Header 76 CurrentHeader() *types.Header 77 GetTdByHash(hash common.Hash) *big.Int 78 InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) 79 Rollback(chain []common.Hash) 80 Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) 81 GetHeaderByNumber(number uint64) *types.Header 82 GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash 83 LastBlockHash() common.Hash 84 Genesis() *types.Block 85 SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription 86 } 87 88 type txPool interface { 89 // AddRemotes should add the given transactions to the pool. 90 AddRemotes([]*types.Transaction) error 91 } 92 93 type ProtocolManager struct { 94 lightSync bool 95 txpool txPool 96 txrelay *LesTxRelay 97 networkId uint64 98 chainConfig *params.ChainConfig 99 blockchain BlockChain 100 chainDb ethdb.Database 101 odr *LesOdr 102 server *LesServer 103 serverPool *serverPool 104 lesTopic discv5.Topic 105 reqDist *requestDistributor 106 retriever *retrieveManager 107 108 downloader *downloader.Downloader 109 fetcher *lightFetcher 110 peers *peerSet 111 112 SubProtocols []p2p.Protocol 113 114 eventMux *event.TypeMux 115 116 // channels for fetcher, syncer, txsyncLoop 117 newPeerCh chan *peer 118 quitSync chan struct{} 119 noMorePeers chan struct{} 120 121 // wait group is used for graceful shutdowns during downloading 122 // and processing 123 wg *sync.WaitGroup 124 } 125 126 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable 127 // with the ethereum network. 128 func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, 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) { 129 // Create the protocol manager with the base fields 130 manager := &ProtocolManager{ 131 lightSync: lightSync, 132 eventMux: mux, 133 blockchain: blockchain, 134 chainConfig: chainConfig, 135 chainDb: chainDb, 136 odr: odr, 137 networkId: networkId, 138 txpool: txpool, 139 txrelay: txrelay, 140 peers: peers, 141 newPeerCh: make(chan *peer), 142 quitSync: quitSync, 143 wg: wg, 144 noMorePeers: make(chan struct{}), 145 } 146 if odr != nil { 147 manager.retriever = odr.retriever 148 manager.reqDist = odr.retriever.dist 149 } 150 // Initiate a sub-protocol for every implemented version we can handle 151 manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions)) 152 for i, version := range ProtocolVersions { 153 // Compatible, initialize the sub-protocol 154 version := version // Closure for the run 155 manager.SubProtocols = append(manager.SubProtocols, p2p.Protocol{ 156 Name: "les", 157 Version: version, 158 Length: ProtocolLengths[i], 159 Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { 160 var entry *poolEntry 161 peer := manager.newPeer(int(version), networkId, p, rw) 162 if manager.serverPool != nil { 163 addr := p.RemoteAddr().(*net.TCPAddr) 164 entry = manager.serverPool.connect(peer, addr.IP, uint16(addr.Port)) 165 } 166 peer.poolEntry = entry 167 select { 168 case manager.newPeerCh <- peer: 169 manager.wg.Add(1) 170 defer manager.wg.Done() 171 err := manager.handle(peer) 172 if entry != nil { 173 manager.serverPool.disconnect(entry) 174 } 175 return err 176 case <-manager.quitSync: 177 if entry != nil { 178 manager.serverPool.disconnect(entry) 179 } 180 return p2p.DiscQuitting 181 } 182 }, 183 NodeInfo: func() interface{} { 184 return manager.NodeInfo() 185 }, 186 PeerInfo: func(id discover.NodeID) interface{} { 187 if p := manager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil { 188 return p.Info() 189 } 190 return nil 191 }, 192 }) 193 } 194 if len(manager.SubProtocols) == 0 { 195 return nil, errIncompatibleConfig 196 } 197 198 removePeer := manager.removePeer 199 if disableClientRemovePeer { 200 removePeer = func(id string) {} 201 } 202 203 if lightSync { 204 manager.downloader = downloader.New(downloader.LightSync, chainDb, manager.eventMux, nil, blockchain, removePeer) 205 manager.peers.notify((*downloaderPeerNotify)(manager)) 206 manager.fetcher = newLightFetcher(manager) 207 } 208 209 return manager, nil 210 } 211 212 // removePeer initiates disconnection from a peer by removing it from the peer set 213 func (pm *ProtocolManager) removePeer(id string) { 214 pm.peers.Unregister(id) 215 } 216 217 func (pm *ProtocolManager) Start() { 218 if pm.lightSync { 219 go pm.syncer() 220 } else { 221 go func() { 222 for range pm.newPeerCh { 223 } 224 }() 225 } 226 } 227 228 func (pm *ProtocolManager) Stop() { 229 // Showing a log message. During download / process this could actually 230 // take between 5 to 10 seconds and therefor feedback is required. 231 log.Info("Stopping light Wanchain protocol") 232 233 // Quit the sync loop. 234 // After this send has completed, no new peers will be accepted. 235 pm.noMorePeers <- struct{}{} 236 237 close(pm.quitSync) // quits syncer, fetcher 238 239 // Disconnect existing sessions. 240 // This also closes the gate for any new registrations on the peer set. 241 // sessions which are already established but not added to pm.peers yet 242 // will exit when they try to register. 243 pm.peers.Close() 244 245 // Wait for any process action 246 pm.wg.Wait() 247 248 log.Info("Light Wanchain protocol stopped") 249 } 250 251 func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { 252 return newPeer(pv, nv, p, newMeteredMsgWriter(rw)) 253 } 254 255 // handle is the callback invoked to manage the life cycle of a les peer. When 256 // this function terminates, the peer is disconnected. 257 func (pm *ProtocolManager) handle(p *peer) error { 258 p.Log().Debug("Light Wanchain peer connected", "name", p.Name()) 259 260 // Execute the LES handshake 261 td, head, genesis := pm.blockchain.Status() 262 headNum := core.GetBlockNumber(pm.chainDb, head) 263 if err := p.Handshake(td, head, headNum, genesis, pm.server); err != nil { 264 p.Log().Debug("Light Ethereum handshake failed", "err", err) 265 return err 266 } 267 if rw, ok := p.rw.(*meteredMsgReadWriter); ok { 268 rw.Init(p.version) 269 } 270 // Register the peer locally 271 if err := pm.peers.Register(p); err != nil { 272 p.Log().Error("Light Wanchain peer registration failed", "err", err) 273 return err 274 } 275 defer func() { 276 if pm.server != nil && pm.server.fcManager != nil && p.fcClient != nil { 277 p.fcClient.Remove(pm.server.fcManager) 278 } 279 pm.removePeer(p.id) 280 }() 281 // Register the peer in the downloader. If the downloader considers it banned, we disconnect 282 if pm.lightSync { 283 p.lock.Lock() 284 head := p.headInfo 285 p.lock.Unlock() 286 if pm.fetcher != nil { 287 pm.fetcher.announce(p, head) 288 } 289 290 if p.poolEntry != nil { 291 pm.serverPool.registered(p.poolEntry) 292 } 293 } 294 295 stop := make(chan struct{}) 296 defer close(stop) 297 go func() { 298 // new block announce loop 299 for { 300 select { 301 case announce := <-p.announceChn: 302 p.SendAnnounce(announce) 303 case <-stop: 304 return 305 } 306 } 307 }() 308 309 // main loop. handle incoming messages. 310 for { 311 if err := pm.handleMsg(p); err != nil { 312 p.Log().Debug("Light Ethereum message handling failed", "err", err) 313 return err 314 } 315 } 316 } 317 318 var reqList = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, GetProofsMsg, SendTxMsg, GetHeaderProofsMsg} 319 320 // handleMsg is invoked whenever an inbound message is received from a remote 321 // peer. The remote connection is torn down upon returning any error. 322 func (pm *ProtocolManager) handleMsg(p *peer) error { 323 // Read the next message from the remote peer, and ensure it's fully consumed 324 msg, err := p.rw.ReadMsg() 325 if err != nil { 326 return err 327 } 328 p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size) 329 330 costs := p.fcCosts[msg.Code] 331 reject := func(reqCnt, maxCnt uint64) bool { 332 if p.fcClient == nil || reqCnt > maxCnt { 333 return true 334 } 335 bufValue, _ := p.fcClient.AcceptRequest() 336 cost := costs.baseCost + reqCnt*costs.reqCost 337 if cost > pm.server.defParams.BufLimit { 338 cost = pm.server.defParams.BufLimit 339 } 340 if cost > bufValue { 341 recharge := time.Duration((cost - bufValue) * 1000000 / pm.server.defParams.MinRecharge) 342 p.Log().Error("Request came too early", "recharge", common.PrettyDuration(recharge)) 343 return true 344 } 345 return false 346 } 347 348 if msg.Size > ProtocolMaxMsgSize { 349 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 350 } 351 defer msg.Discard() 352 353 var deliverMsg *Msg 354 355 // Handle the message depending on its contents 356 switch msg.Code { 357 case StatusMsg: 358 p.Log().Trace("Received status message") 359 // Status messages should never arrive after the handshake 360 return errResp(ErrExtraStatusMsg, "uncontrolled status message") 361 362 // Block header query, collect the requested headers and reply 363 case AnnounceMsg: 364 p.Log().Trace("Received announce message") 365 366 var req announceData 367 if err := msg.Decode(&req); err != nil { 368 return errResp(ErrDecode, "%v: %v", msg, err) 369 } 370 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 371 if pm.fetcher != nil { 372 pm.fetcher.announce(p, &req) 373 } 374 375 case GetBlockHeadersMsg: 376 p.Log().Trace("Received block header request") 377 // Decode the complex header query 378 var req struct { 379 ReqID uint64 380 Query getBlockHeadersData 381 } 382 if err := msg.Decode(&req); err != nil { 383 return errResp(ErrDecode, "%v: %v", msg, err) 384 } 385 386 query := req.Query 387 if reject(query.Amount, MaxHeaderFetch) { 388 return errResp(ErrRequestRejected, "") 389 } 390 391 hashMode := query.Origin.Hash != (common.Hash{}) 392 393 // Gather headers until the fetch or network limits is reached 394 var ( 395 bytes common.StorageSize 396 headers []*types.Header 397 unknown bool 398 ) 399 for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit { 400 // Retrieve the next header satisfying the query 401 var origin *types.Header 402 if hashMode { 403 origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) 404 } else { 405 origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) 406 } 407 if origin == nil { 408 break 409 } 410 number := origin.Number.Uint64() 411 headers = append(headers, origin) 412 bytes += estHeaderRlpSize 413 414 // Advance to the next header of the query 415 switch { 416 case query.Origin.Hash != (common.Hash{}) && query.Reverse: 417 // Hash based traversal towards the genesis block 418 for i := 0; i < int(query.Skip)+1; i++ { 419 if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil { 420 query.Origin.Hash = header.ParentHash 421 number-- 422 } else { 423 unknown = true 424 break 425 } 426 } 427 case query.Origin.Hash != (common.Hash{}) && !query.Reverse: 428 // Hash based traversal towards the leaf block 429 if header := pm.blockchain.GetHeaderByNumber(origin.Number.Uint64() + query.Skip + 1); header != nil { 430 if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { 431 query.Origin.Hash = header.Hash() 432 } else { 433 unknown = true 434 } 435 } else { 436 unknown = true 437 } 438 case query.Reverse: 439 // Number based traversal towards the genesis block 440 if query.Origin.Number >= query.Skip+1 { 441 query.Origin.Number -= (query.Skip + 1) 442 } else { 443 unknown = true 444 } 445 446 case !query.Reverse: 447 // Number based traversal towards the leaf block 448 query.Origin.Number += (query.Skip + 1) 449 } 450 } 451 452 bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + query.Amount*costs.reqCost) 453 pm.server.fcCostStats.update(msg.Code, query.Amount, rcost) 454 return p.SendBlockHeaders(req.ReqID, bv, headers) 455 456 case BlockHeadersMsg: 457 if pm.downloader == nil { 458 return errResp(ErrUnexpectedResponse, "") 459 } 460 461 p.Log().Trace("Received block header response message") 462 // A batch of headers arrived to one of our previous requests 463 var resp struct { 464 ReqID, BV uint64 465 Headers []*types.Header 466 } 467 if err := msg.Decode(&resp); err != nil { 468 return errResp(ErrDecode, "msg %v: %v", msg, err) 469 } 470 p.fcServer.GotReply(resp.ReqID, resp.BV) 471 if pm.fetcher != nil && pm.fetcher.requestedID(resp.ReqID) { 472 pm.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 473 } else { 474 err := pm.downloader.DeliverHeaders(p.id, resp.Headers) 475 if err != nil { 476 log.Debug(fmt.Sprint(err)) 477 } 478 } 479 480 case GetBlockBodiesMsg: 481 p.Log().Trace("Received block bodies request") 482 // Decode the retrieval message 483 var req struct { 484 ReqID uint64 485 Hashes []common.Hash 486 } 487 if err := msg.Decode(&req); err != nil { 488 return errResp(ErrDecode, "msg %v: %v", msg, err) 489 } 490 // Gather blocks until the fetch or network limits is reached 491 var ( 492 bytes int 493 bodies []rlp.RawValue 494 ) 495 reqCnt := len(req.Hashes) 496 if reject(uint64(reqCnt), MaxBodyFetch) { 497 return errResp(ErrRequestRejected, "") 498 } 499 for _, hash := range req.Hashes { 500 if bytes >= softResponseLimit { 501 break 502 } 503 // Retrieve the requested block body, stopping if enough was found 504 if data := core.GetBodyRLP(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)); len(data) != 0 { 505 bodies = append(bodies, data) 506 bytes += len(data) 507 } 508 } 509 bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) 510 pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) 511 return p.SendBlockBodiesRLP(req.ReqID, bv, bodies) 512 513 case BlockBodiesMsg: 514 if pm.odr == nil { 515 return errResp(ErrUnexpectedResponse, "") 516 } 517 518 p.Log().Trace("Received block bodies response") 519 // A batch of block bodies arrived to one of our previous requests 520 var resp struct { 521 ReqID, BV uint64 522 Data []*types.Body 523 } 524 if err := msg.Decode(&resp); err != nil { 525 return errResp(ErrDecode, "msg %v: %v", msg, err) 526 } 527 p.fcServer.GotReply(resp.ReqID, resp.BV) 528 deliverMsg = &Msg{ 529 MsgType: MsgBlockBodies, 530 ReqID: resp.ReqID, 531 Obj: resp.Data, 532 } 533 534 case GetCodeMsg: 535 p.Log().Trace("Received code request") 536 // Decode the retrieval message 537 var req struct { 538 ReqID uint64 539 Reqs []CodeReq 540 } 541 if err := msg.Decode(&req); err != nil { 542 return errResp(ErrDecode, "msg %v: %v", msg, err) 543 } 544 // Gather state data until the fetch or network limits is reached 545 var ( 546 bytes int 547 data [][]byte 548 ) 549 reqCnt := len(req.Reqs) 550 if reject(uint64(reqCnt), MaxCodeFetch) { 551 return errResp(ErrRequestRejected, "") 552 } 553 for _, req := range req.Reqs { 554 // Retrieve the requested state entry, stopping if enough was found 555 if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { 556 if trie, _ := trie.New(header.Root, pm.chainDb); trie != nil { 557 sdata := trie.Get(req.AccKey) 558 var acc state.Account 559 if err := rlp.DecodeBytes(sdata, &acc); err == nil { 560 entry, _ := pm.chainDb.Get(acc.CodeHash) 561 if bytes+len(entry) >= softResponseLimit { 562 break 563 } 564 data = append(data, entry) 565 bytes += len(entry) 566 } 567 } 568 } 569 } 570 bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) 571 pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) 572 return p.SendCode(req.ReqID, bv, data) 573 574 case CodeMsg: 575 if pm.odr == nil { 576 return errResp(ErrUnexpectedResponse, "") 577 } 578 579 p.Log().Trace("Received code response") 580 // A batch of node state data arrived to one of our previous requests 581 var resp struct { 582 ReqID, BV uint64 583 Data [][]byte 584 } 585 if err := msg.Decode(&resp); err != nil { 586 return errResp(ErrDecode, "msg %v: %v", msg, err) 587 } 588 p.fcServer.GotReply(resp.ReqID, resp.BV) 589 deliverMsg = &Msg{ 590 MsgType: MsgCode, 591 ReqID: resp.ReqID, 592 Obj: resp.Data, 593 } 594 595 case GetReceiptsMsg: 596 p.Log().Trace("Received receipts request") 597 // Decode the retrieval message 598 var req struct { 599 ReqID uint64 600 Hashes []common.Hash 601 } 602 if err := msg.Decode(&req); err != nil { 603 return errResp(ErrDecode, "msg %v: %v", msg, err) 604 } 605 // Gather state data until the fetch or network limits is reached 606 var ( 607 bytes int 608 receipts []rlp.RawValue 609 ) 610 reqCnt := len(req.Hashes) 611 if reject(uint64(reqCnt), MaxReceiptFetch) { 612 return errResp(ErrRequestRejected, "") 613 } 614 for _, hash := range req.Hashes { 615 if bytes >= softResponseLimit { 616 break 617 } 618 // Retrieve the requested block's receipts, skipping if unknown to us 619 results := core.GetBlockReceipts(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)) 620 if results == nil { 621 if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { 622 continue 623 } 624 } 625 // If known, encode and queue for response packet 626 if encoded, err := rlp.EncodeToBytes(results); err != nil { 627 log.Error("Failed to encode receipt", "err", err) 628 } else { 629 receipts = append(receipts, encoded) 630 bytes += len(encoded) 631 } 632 } 633 bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) 634 pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) 635 return p.SendReceiptsRLP(req.ReqID, bv, receipts) 636 637 case ReceiptsMsg: 638 if pm.odr == nil { 639 return errResp(ErrUnexpectedResponse, "") 640 } 641 642 p.Log().Trace("Received receipts response") 643 // A batch of receipts arrived to one of our previous requests 644 var resp struct { 645 ReqID, BV uint64 646 Receipts []types.Receipts 647 } 648 if err := msg.Decode(&resp); err != nil { 649 return errResp(ErrDecode, "msg %v: %v", msg, err) 650 } 651 p.fcServer.GotReply(resp.ReqID, resp.BV) 652 deliverMsg = &Msg{ 653 MsgType: MsgReceipts, 654 ReqID: resp.ReqID, 655 Obj: resp.Receipts, 656 } 657 658 case GetProofsMsg: 659 p.Log().Trace("Received proofs request") 660 // Decode the retrieval message 661 var req struct { 662 ReqID uint64 663 Reqs []ProofReq 664 } 665 if err := msg.Decode(&req); err != nil { 666 return errResp(ErrDecode, "msg %v: %v", msg, err) 667 } 668 // Gather state data until the fetch or network limits is reached 669 var ( 670 bytes int 671 proofs proofsData 672 ) 673 reqCnt := len(req.Reqs) 674 if reject(uint64(reqCnt), MaxProofsFetch) { 675 return errResp(ErrRequestRejected, "") 676 } 677 for _, req := range req.Reqs { 678 if bytes >= softResponseLimit { 679 break 680 } 681 // Retrieve the requested state entry, stopping if enough was found 682 if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { 683 if tr, _ := trie.New(header.Root, pm.chainDb); tr != nil { 684 if len(req.AccKey) > 0 { 685 sdata := tr.Get(req.AccKey) 686 tr = nil 687 var acc state.Account 688 if err := rlp.DecodeBytes(sdata, &acc); err == nil { 689 tr, _ = trie.New(acc.Root, pm.chainDb) 690 } 691 } 692 if tr != nil { 693 proof := tr.Prove(req.Key) 694 proofs = append(proofs, proof) 695 bytes += len(proof) 696 } 697 } 698 } 699 } 700 bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) 701 pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) 702 return p.SendProofs(req.ReqID, bv, proofs) 703 704 case ProofsMsg: 705 if pm.odr == nil { 706 return errResp(ErrUnexpectedResponse, "") 707 } 708 709 p.Log().Trace("Received proofs response") 710 // A batch of merkle proofs arrived to one of our previous requests 711 var resp struct { 712 ReqID, BV uint64 713 Data [][]rlp.RawValue 714 } 715 if err := msg.Decode(&resp); err != nil { 716 return errResp(ErrDecode, "msg %v: %v", msg, err) 717 } 718 p.fcServer.GotReply(resp.ReqID, resp.BV) 719 deliverMsg = &Msg{ 720 MsgType: MsgProofs, 721 ReqID: resp.ReqID, 722 Obj: resp.Data, 723 } 724 725 case GetHeaderProofsMsg: 726 p.Log().Trace("Received headers proof request") 727 // Decode the retrieval message 728 var req struct { 729 ReqID uint64 730 Reqs []ChtReq 731 } 732 if err := msg.Decode(&req); err != nil { 733 return errResp(ErrDecode, "msg %v: %v", msg, err) 734 } 735 // Gather state data until the fetch or network limits is reached 736 var ( 737 bytes int 738 proofs []ChtResp 739 ) 740 reqCnt := len(req.Reqs) 741 if reject(uint64(reqCnt), MaxHeaderProofsFetch) { 742 return errResp(ErrRequestRejected, "") 743 } 744 for _, req := range req.Reqs { 745 if bytes >= softResponseLimit { 746 break 747 } 748 749 if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil { 750 if root := getChtRoot(pm.chainDb, req.ChtNum); root != (common.Hash{}) { 751 if tr, _ := trie.New(root, pm.chainDb); tr != nil { 752 var encNumber [8]byte 753 binary.BigEndian.PutUint64(encNumber[:], req.BlockNum) 754 proof := tr.Prove(encNumber[:]) 755 proofs = append(proofs, ChtResp{Header: header, Proof: proof}) 756 bytes += len(proof) + estHeaderRlpSize 757 } 758 } 759 } 760 } 761 bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) 762 pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) 763 return p.SendHeaderProofs(req.ReqID, bv, proofs) 764 765 case HeaderProofsMsg: 766 if pm.odr == nil { 767 return errResp(ErrUnexpectedResponse, "") 768 } 769 770 p.Log().Trace("Received headers proof response") 771 var resp struct { 772 ReqID, BV uint64 773 Data []ChtResp 774 } 775 if err := msg.Decode(&resp); err != nil { 776 return errResp(ErrDecode, "msg %v: %v", msg, err) 777 } 778 p.fcServer.GotReply(resp.ReqID, resp.BV) 779 deliverMsg = &Msg{ 780 MsgType: MsgHeaderProofs, 781 ReqID: resp.ReqID, 782 Obj: resp.Data, 783 } 784 785 case SendTxMsg: 786 if pm.txpool == nil { 787 return errResp(ErrUnexpectedResponse, "") 788 } 789 // Transactions arrived, parse all of them and deliver to the pool 790 var txs []*types.Transaction 791 if err := msg.Decode(&txs); err != nil { 792 return errResp(ErrDecode, "msg %v: %v", msg, err) 793 } 794 reqCnt := len(txs) 795 if reject(uint64(reqCnt), MaxTxSend) { 796 return errResp(ErrRequestRejected, "") 797 } 798 799 if err := pm.txpool.AddRemotes(txs); err != nil { 800 return errResp(ErrUnexpectedResponse, "msg: %v", err) 801 } 802 803 _, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) 804 pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) 805 806 default: 807 p.Log().Trace("Received unknown message", "code", msg.Code) 808 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 809 } 810 811 if deliverMsg != nil { 812 err := pm.retriever.deliver(p, deliverMsg) 813 if err != nil { 814 p.responseErrors++ 815 if p.responseErrors > maxResponseErrors { 816 return err 817 } 818 } 819 } 820 return nil 821 } 822 823 // NodeInfo retrieves some protocol metadata about the running host node. 824 func (self *ProtocolManager) NodeInfo() *eth.EthNodeInfo { 825 return ð.EthNodeInfo{ 826 Network: self.networkId, 827 Difficulty: self.blockchain.GetTdByHash(self.blockchain.LastBlockHash()), 828 Genesis: self.blockchain.Genesis().Hash(), 829 Head: self.blockchain.LastBlockHash(), 830 } 831 } 832 833 // downloaderPeerNotify implements peerSetNotify 834 type downloaderPeerNotify ProtocolManager 835 836 type peerConnection struct { 837 manager *ProtocolManager 838 peer *peer 839 } 840 841 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 842 return pc.peer.HeadAndTd() 843 } 844 845 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 846 reqID := genReqID() 847 rq := &distReq{ 848 getCost: func(dp distPeer) uint64 { 849 peer := dp.(*peer) 850 return peer.GetRequestCost(GetBlockHeadersMsg, amount) 851 }, 852 canSend: func(dp distPeer) bool { 853 return dp.(*peer) == pc.peer 854 }, 855 request: func(dp distPeer) func() { 856 peer := dp.(*peer) 857 cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) 858 peer.fcServer.QueueRequest(reqID, cost) 859 return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) } 860 }, 861 } 862 _, ok := <-pc.manager.reqDist.queue(rq) 863 if !ok { 864 return ErrNoPeers 865 } 866 return nil 867 } 868 869 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 870 reqID := genReqID() 871 rq := &distReq{ 872 getCost: func(dp distPeer) uint64 { 873 peer := dp.(*peer) 874 return peer.GetRequestCost(GetBlockHeadersMsg, amount) 875 }, 876 canSend: func(dp distPeer) bool { 877 return dp.(*peer) == pc.peer 878 }, 879 request: func(dp distPeer) func() { 880 peer := dp.(*peer) 881 cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) 882 peer.fcServer.QueueRequest(reqID, cost) 883 return func() { peer.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) } 884 }, 885 } 886 _, ok := <-pc.manager.reqDist.queue(rq) 887 if !ok { 888 return ErrNoPeers 889 } 890 return nil 891 } 892 893 func (d *downloaderPeerNotify) registerPeer(p *peer) { 894 pm := (*ProtocolManager)(d) 895 pc := &peerConnection{ 896 manager: pm, 897 peer: p, 898 } 899 pm.downloader.RegisterLightPeer(p.id, ethVersion, pc) 900 } 901 902 func (d *downloaderPeerNotify) unregisterPeer(p *peer) { 903 pm := (*ProtocolManager)(d) 904 pm.downloader.UnregisterPeer(p.id) 905 }