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