github.com/ethereum/go-ethereum@v1.10.9/les/client_handler.go (about) 1 // Copyright 2019 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 18 19 import ( 20 "context" 21 "math/big" 22 "math/rand" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/mclock" 29 "github.com/ethereum/go-ethereum/core/forkid" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/eth/protocols/eth" 32 "github.com/ethereum/go-ethereum/les/downloader" 33 "github.com/ethereum/go-ethereum/light" 34 "github.com/ethereum/go-ethereum/log" 35 "github.com/ethereum/go-ethereum/p2p" 36 "github.com/ethereum/go-ethereum/params" 37 ) 38 39 // clientHandler is responsible for receiving and processing all incoming server 40 // responses. 41 type clientHandler struct { 42 ulc *ulc 43 forkFilter forkid.Filter 44 checkpoint *params.TrustedCheckpoint 45 fetcher *lightFetcher 46 downloader *downloader.Downloader 47 backend *LightEthereum 48 49 closeCh chan struct{} 50 wg sync.WaitGroup // WaitGroup used to track all connected peers. 51 52 // Hooks used in the testing 53 syncStart func(header *types.Header) // Hook called when the syncing is started 54 syncEnd func(header *types.Header) // Hook called when the syncing is done 55 } 56 57 func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEthereum) *clientHandler { 58 handler := &clientHandler{ 59 forkFilter: forkid.NewFilter(backend.blockchain), 60 checkpoint: checkpoint, 61 backend: backend, 62 closeCh: make(chan struct{}), 63 } 64 if ulcServers != nil { 65 ulc, err := newULC(ulcServers, ulcFraction) 66 if err != nil { 67 log.Error("Failed to initialize ultra light client") 68 } 69 handler.ulc = ulc 70 log.Info("Enable ultra light client mode") 71 } 72 var height uint64 73 if checkpoint != nil { 74 height = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1 75 } 76 handler.fetcher = newLightFetcher(backend.blockchain, backend.engine, backend.peers, handler.ulc, backend.chainDb, backend.reqDist, handler.synchronise) 77 handler.downloader = downloader.New(height, backend.chainDb, nil, backend.eventMux, nil, backend.blockchain, handler.removePeer) 78 handler.backend.peers.subscribe((*downloaderPeerNotify)(handler)) 79 return handler 80 } 81 82 func (h *clientHandler) start() { 83 h.fetcher.start() 84 } 85 86 func (h *clientHandler) stop() { 87 close(h.closeCh) 88 h.downloader.Terminate() 89 h.fetcher.stop() 90 h.wg.Wait() 91 } 92 93 // runPeer is the p2p protocol run function for the given version. 94 func (h *clientHandler) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error { 95 trusted := false 96 if h.ulc != nil { 97 trusted = h.ulc.trusted(p.ID()) 98 } 99 peer := newServerPeer(int(version), h.backend.config.NetworkId, trusted, p, newMeteredMsgWriter(rw, int(version))) 100 defer peer.close() 101 h.wg.Add(1) 102 defer h.wg.Done() 103 err := h.handle(peer, false) 104 return err 105 } 106 107 func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error { 108 if h.backend.peers.len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted { 109 return p2p.DiscTooManyPeers 110 } 111 p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) 112 113 // Execute the LES handshake 114 forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64()) 115 if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil { 116 p.Log().Debug("Light Ethereum handshake failed", "err", err) 117 return err 118 } 119 // Register peer with the server pool 120 if h.backend.serverPool != nil { 121 if nvt, err := h.backend.serverPool.RegisterNode(p.Node()); err == nil { 122 p.setValueTracker(nvt) 123 p.updateVtParams() 124 defer func() { 125 p.setValueTracker(nil) 126 h.backend.serverPool.UnregisterNode(p.Node()) 127 }() 128 } else { 129 return err 130 } 131 } 132 // Register the peer locally 133 if err := h.backend.peers.register(p); err != nil { 134 p.Log().Error("Light Ethereum peer registration failed", "err", err) 135 return err 136 } 137 138 serverConnectionGauge.Update(int64(h.backend.peers.len())) 139 140 connectedAt := mclock.Now() 141 defer func() { 142 h.backend.peers.unregister(p.id) 143 connectionTimer.Update(time.Duration(mclock.Now() - connectedAt)) 144 serverConnectionGauge.Update(int64(h.backend.peers.len())) 145 }() 146 // It's mainly used in testing which requires discarding initial 147 // signal to prevent syncing. 148 if !noInitAnnounce { 149 h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td}) 150 } 151 // Mark the peer starts to be served. 152 atomic.StoreUint32(&p.serving, 1) 153 defer atomic.StoreUint32(&p.serving, 0) 154 155 // Spawn a main loop to handle all incoming messages. 156 for { 157 if err := h.handleMsg(p); err != nil { 158 p.Log().Debug("Light Ethereum message handling failed", "err", err) 159 p.fcServer.DumpLogs() 160 return err 161 } 162 } 163 } 164 165 // handleMsg is invoked whenever an inbound message is received from a remote 166 // peer. The remote connection is torn down upon returning any error. 167 func (h *clientHandler) handleMsg(p *serverPeer) error { 168 // Read the next message from the remote peer, and ensure it's fully consumed 169 msg, err := p.rw.ReadMsg() 170 if err != nil { 171 return err 172 } 173 p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size) 174 175 if msg.Size > ProtocolMaxMsgSize { 176 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 177 } 178 defer msg.Discard() 179 180 var deliverMsg *Msg 181 182 // Handle the message depending on its contents 183 switch { 184 case msg.Code == AnnounceMsg: 185 p.Log().Trace("Received announce message") 186 var req announceData 187 if err := msg.Decode(&req); err != nil { 188 return errResp(ErrDecode, "%v: %v", msg, err) 189 } 190 if err := req.sanityCheck(); err != nil { 191 return err 192 } 193 update, size := req.Update.decode() 194 if p.rejectUpdate(size) { 195 return errResp(ErrRequestRejected, "") 196 } 197 p.updateFlowControl(update) 198 p.updateVtParams() 199 200 if req.Hash != (common.Hash{}) { 201 if p.announceType == announceTypeNone { 202 return errResp(ErrUnexpectedResponse, "") 203 } 204 if p.announceType == announceTypeSigned { 205 if err := req.checkSignature(p.ID(), update); err != nil { 206 p.Log().Trace("Invalid announcement signature", "err", err) 207 return err 208 } 209 p.Log().Trace("Valid announcement signature") 210 } 211 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 212 213 // Update peer head information first and then notify the announcement 214 p.updateHead(req.Hash, req.Number, req.Td) 215 h.fetcher.announce(p, &req) 216 } 217 case msg.Code == BlockHeadersMsg: 218 p.Log().Trace("Received block header response message") 219 var resp struct { 220 ReqID, BV uint64 221 Headers []*types.Header 222 } 223 if err := msg.Decode(&resp); err != nil { 224 return errResp(ErrDecode, "msg %v: %v", msg, err) 225 } 226 headers := resp.Headers 227 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 228 p.answeredRequest(resp.ReqID) 229 230 // Filter out the explicitly requested header by the retriever 231 if h.backend.retriever.requested(resp.ReqID) { 232 deliverMsg = &Msg{ 233 MsgType: MsgBlockHeaders, 234 ReqID: resp.ReqID, 235 Obj: resp.Headers, 236 } 237 } else { 238 // Filter out any explicitly requested headers, deliver the rest to the downloader 239 filter := len(headers) == 1 240 if filter { 241 headers = h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 242 } 243 if len(headers) != 0 || !filter { 244 if err := h.downloader.DeliverHeaders(p.id, headers); err != nil { 245 log.Debug("Failed to deliver headers", "err", err) 246 } 247 } 248 } 249 case msg.Code == BlockBodiesMsg: 250 p.Log().Trace("Received block bodies response") 251 var resp struct { 252 ReqID, BV uint64 253 Data []*types.Body 254 } 255 if err := msg.Decode(&resp); err != nil { 256 return errResp(ErrDecode, "msg %v: %v", msg, err) 257 } 258 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 259 p.answeredRequest(resp.ReqID) 260 deliverMsg = &Msg{ 261 MsgType: MsgBlockBodies, 262 ReqID: resp.ReqID, 263 Obj: resp.Data, 264 } 265 case msg.Code == CodeMsg: 266 p.Log().Trace("Received code response") 267 var resp struct { 268 ReqID, BV uint64 269 Data [][]byte 270 } 271 if err := msg.Decode(&resp); err != nil { 272 return errResp(ErrDecode, "msg %v: %v", msg, err) 273 } 274 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 275 p.answeredRequest(resp.ReqID) 276 deliverMsg = &Msg{ 277 MsgType: MsgCode, 278 ReqID: resp.ReqID, 279 Obj: resp.Data, 280 } 281 case msg.Code == ReceiptsMsg: 282 p.Log().Trace("Received receipts response") 283 var resp struct { 284 ReqID, BV uint64 285 Receipts []types.Receipts 286 } 287 if err := msg.Decode(&resp); err != nil { 288 return errResp(ErrDecode, "msg %v: %v", msg, err) 289 } 290 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 291 p.answeredRequest(resp.ReqID) 292 deliverMsg = &Msg{ 293 MsgType: MsgReceipts, 294 ReqID: resp.ReqID, 295 Obj: resp.Receipts, 296 } 297 case msg.Code == ProofsV2Msg: 298 p.Log().Trace("Received les/2 proofs response") 299 var resp struct { 300 ReqID, BV uint64 301 Data light.NodeList 302 } 303 if err := msg.Decode(&resp); err != nil { 304 return errResp(ErrDecode, "msg %v: %v", msg, err) 305 } 306 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 307 p.answeredRequest(resp.ReqID) 308 deliverMsg = &Msg{ 309 MsgType: MsgProofsV2, 310 ReqID: resp.ReqID, 311 Obj: resp.Data, 312 } 313 case msg.Code == HelperTrieProofsMsg: 314 p.Log().Trace("Received helper trie proof response") 315 var resp struct { 316 ReqID, BV uint64 317 Data HelperTrieResps 318 } 319 if err := msg.Decode(&resp); err != nil { 320 return errResp(ErrDecode, "msg %v: %v", msg, err) 321 } 322 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 323 p.answeredRequest(resp.ReqID) 324 deliverMsg = &Msg{ 325 MsgType: MsgHelperTrieProofs, 326 ReqID: resp.ReqID, 327 Obj: resp.Data, 328 } 329 case msg.Code == TxStatusMsg: 330 p.Log().Trace("Received tx status response") 331 var resp struct { 332 ReqID, BV uint64 333 Status []light.TxStatus 334 } 335 if err := msg.Decode(&resp); err != nil { 336 return errResp(ErrDecode, "msg %v: %v", msg, err) 337 } 338 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 339 p.answeredRequest(resp.ReqID) 340 deliverMsg = &Msg{ 341 MsgType: MsgTxStatus, 342 ReqID: resp.ReqID, 343 Obj: resp.Status, 344 } 345 case msg.Code == StopMsg && p.version >= lpv3: 346 p.freeze() 347 h.backend.retriever.frozen(p) 348 p.Log().Debug("Service stopped") 349 case msg.Code == ResumeMsg && p.version >= lpv3: 350 var bv uint64 351 if err := msg.Decode(&bv); err != nil { 352 return errResp(ErrDecode, "msg %v: %v", msg, err) 353 } 354 p.fcServer.ResumeFreeze(bv) 355 p.unfreeze() 356 p.Log().Debug("Service resumed") 357 default: 358 p.Log().Trace("Received invalid message", "code", msg.Code) 359 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 360 } 361 // Deliver the received response to retriever. 362 if deliverMsg != nil { 363 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 364 if val := p.errCount.Add(1, mclock.Now()); val > maxResponseErrors { 365 return err 366 } 367 } 368 } 369 return nil 370 } 371 372 func (h *clientHandler) removePeer(id string) { 373 h.backend.peers.unregister(id) 374 } 375 376 type peerConnection struct { 377 handler *clientHandler 378 peer *serverPeer 379 } 380 381 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 382 return pc.peer.HeadAndTd() 383 } 384 385 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 386 rq := &distReq{ 387 getCost: func(dp distPeer) uint64 { 388 peer := dp.(*serverPeer) 389 return peer.getRequestCost(GetBlockHeadersMsg, amount) 390 }, 391 canSend: func(dp distPeer) bool { 392 return dp.(*serverPeer) == pc.peer 393 }, 394 request: func(dp distPeer) func() { 395 reqID := rand.Uint64() 396 peer := dp.(*serverPeer) 397 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 398 peer.fcServer.QueuedRequest(reqID, cost) 399 return func() { peer.requestHeadersByHash(reqID, origin, amount, skip, reverse) } 400 }, 401 } 402 _, ok := <-pc.handler.backend.reqDist.queue(rq) 403 if !ok { 404 return light.ErrNoPeers 405 } 406 return nil 407 } 408 409 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 410 rq := &distReq{ 411 getCost: func(dp distPeer) uint64 { 412 peer := dp.(*serverPeer) 413 return peer.getRequestCost(GetBlockHeadersMsg, amount) 414 }, 415 canSend: func(dp distPeer) bool { 416 return dp.(*serverPeer) == pc.peer 417 }, 418 request: func(dp distPeer) func() { 419 reqID := rand.Uint64() 420 peer := dp.(*serverPeer) 421 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 422 peer.fcServer.QueuedRequest(reqID, cost) 423 return func() { peer.requestHeadersByNumber(reqID, origin, amount, skip, reverse) } 424 }, 425 } 426 _, ok := <-pc.handler.backend.reqDist.queue(rq) 427 if !ok { 428 return light.ErrNoPeers 429 } 430 return nil 431 } 432 433 // RetrieveSingleHeaderByNumber requests a single header by the specified block 434 // number. This function will wait the response until it's timeout or delivered. 435 func (pc *peerConnection) RetrieveSingleHeaderByNumber(context context.Context, number uint64) (*types.Header, error) { 436 reqID := rand.Uint64() 437 rq := &distReq{ 438 getCost: func(dp distPeer) uint64 { 439 peer := dp.(*serverPeer) 440 return peer.getRequestCost(GetBlockHeadersMsg, 1) 441 }, 442 canSend: func(dp distPeer) bool { 443 return dp.(*serverPeer) == pc.peer 444 }, 445 request: func(dp distPeer) func() { 446 peer := dp.(*serverPeer) 447 cost := peer.getRequestCost(GetBlockHeadersMsg, 1) 448 peer.fcServer.QueuedRequest(reqID, cost) 449 return func() { peer.requestHeadersByNumber(reqID, number, 1, 0, false) } 450 }, 451 } 452 var header *types.Header 453 if err := pc.handler.backend.retriever.retrieve(context, reqID, rq, func(peer distPeer, msg *Msg) error { 454 if msg.MsgType != MsgBlockHeaders { 455 return errInvalidMessageType 456 } 457 headers := msg.Obj.([]*types.Header) 458 if len(headers) != 1 { 459 return errInvalidEntryCount 460 } 461 header = headers[0] 462 return nil 463 }, nil); err != nil { 464 return nil, err 465 } 466 return header, nil 467 } 468 469 // downloaderPeerNotify implements peerSetNotify 470 type downloaderPeerNotify clientHandler 471 472 func (d *downloaderPeerNotify) registerPeer(p *serverPeer) { 473 h := (*clientHandler)(d) 474 pc := &peerConnection{ 475 handler: h, 476 peer: p, 477 } 478 h.downloader.RegisterLightPeer(p.id, eth.ETH66, pc) 479 } 480 481 func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) { 482 h := (*clientHandler)(d) 483 h.downloader.UnregisterPeer(p.id) 484 }