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