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