github.com/hardtosaygoodbye/go-ethereum@v1.10.16-0.20220122011429-97003b9e6c15/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/hardtosaygoodbye/go-ethereum/common" 28 "github.com/hardtosaygoodbye/go-ethereum/common/mclock" 29 "github.com/hardtosaygoodbye/go-ethereum/core/forkid" 30 "github.com/hardtosaygoodbye/go-ethereum/core/types" 31 "github.com/hardtosaygoodbye/go-ethereum/eth/protocols/eth" 32 "github.com/hardtosaygoodbye/go-ethereum/les/downloader" 33 "github.com/hardtosaygoodbye/go-ethereum/light" 34 "github.com/hardtosaygoodbye/go-ethereum/log" 35 "github.com/hardtosaygoodbye/go-ethereum/p2p" 36 "github.com/hardtosaygoodbye/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, 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 147 // Discard all the announces after the transition 148 // Also discarding initial signal to prevent syncing during testing. 149 if !(noInitAnnounce || h.backend.merger.TDDReached()) { 150 h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td}) 151 } 152 153 // Mark the peer starts to be served. 154 atomic.StoreUint32(&p.serving, 1) 155 defer atomic.StoreUint32(&p.serving, 0) 156 157 // Spawn a main loop to handle all incoming messages. 158 for { 159 if err := h.handleMsg(p); err != nil { 160 p.Log().Debug("Light Ethereum message handling failed", "err", err) 161 p.fcServer.DumpLogs() 162 return err 163 } 164 } 165 } 166 167 // handleMsg is invoked whenever an inbound message is received from a remote 168 // peer. The remote connection is torn down upon returning any error. 169 func (h *clientHandler) handleMsg(p *serverPeer) error { 170 // Read the next message from the remote peer, and ensure it's fully consumed 171 msg, err := p.rw.ReadMsg() 172 if err != nil { 173 return err 174 } 175 p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size) 176 177 if msg.Size > ProtocolMaxMsgSize { 178 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 179 } 180 defer msg.Discard() 181 182 var deliverMsg *Msg 183 184 // Handle the message depending on its contents 185 switch { 186 case msg.Code == AnnounceMsg: 187 p.Log().Trace("Received announce message") 188 var req announceData 189 if err := msg.Decode(&req); err != nil { 190 return errResp(ErrDecode, "%v: %v", msg, err) 191 } 192 if err := req.sanityCheck(); err != nil { 193 return err 194 } 195 update, size := req.Update.decode() 196 if p.rejectUpdate(size) { 197 return errResp(ErrRequestRejected, "") 198 } 199 p.updateFlowControl(update) 200 p.updateVtParams() 201 202 if req.Hash != (common.Hash{}) { 203 if p.announceType == announceTypeNone { 204 return errResp(ErrUnexpectedResponse, "") 205 } 206 if p.announceType == announceTypeSigned { 207 if err := req.checkSignature(p.ID(), update); err != nil { 208 p.Log().Trace("Invalid announcement signature", "err", err) 209 return err 210 } 211 p.Log().Trace("Valid announcement signature") 212 } 213 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 214 215 // Update peer head information first and then notify the announcement 216 p.updateHead(req.Hash, req.Number, req.Td) 217 218 // Discard all the announces after the transition 219 if !h.backend.merger.TDDReached() { 220 h.fetcher.announce(p, &req) 221 } 222 } 223 case msg.Code == BlockHeadersMsg: 224 p.Log().Trace("Received block header response message") 225 var resp struct { 226 ReqID, BV uint64 227 Headers []*types.Header 228 } 229 if err := msg.Decode(&resp); err != nil { 230 return errResp(ErrDecode, "msg %v: %v", msg, err) 231 } 232 headers := resp.Headers 233 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 234 p.answeredRequest(resp.ReqID) 235 236 // Filter out the explicitly requested header by the retriever 237 if h.backend.retriever.requested(resp.ReqID) { 238 deliverMsg = &Msg{ 239 MsgType: MsgBlockHeaders, 240 ReqID: resp.ReqID, 241 Obj: resp.Headers, 242 } 243 } else { 244 // Filter out any explicitly requested headers, deliver the rest to the downloader 245 filter := len(headers) == 1 246 if filter { 247 headers = h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 248 } 249 if len(headers) != 0 || !filter { 250 if err := h.downloader.DeliverHeaders(p.id, headers); err != nil { 251 log.Debug("Failed to deliver headers", "err", err) 252 } 253 } 254 } 255 case msg.Code == BlockBodiesMsg: 256 p.Log().Trace("Received block bodies response") 257 var resp struct { 258 ReqID, BV uint64 259 Data []*types.Body 260 } 261 if err := msg.Decode(&resp); err != nil { 262 return errResp(ErrDecode, "msg %v: %v", msg, err) 263 } 264 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 265 p.answeredRequest(resp.ReqID) 266 deliverMsg = &Msg{ 267 MsgType: MsgBlockBodies, 268 ReqID: resp.ReqID, 269 Obj: resp.Data, 270 } 271 case msg.Code == CodeMsg: 272 p.Log().Trace("Received code response") 273 var resp struct { 274 ReqID, BV uint64 275 Data [][]byte 276 } 277 if err := msg.Decode(&resp); err != nil { 278 return errResp(ErrDecode, "msg %v: %v", msg, err) 279 } 280 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 281 p.answeredRequest(resp.ReqID) 282 deliverMsg = &Msg{ 283 MsgType: MsgCode, 284 ReqID: resp.ReqID, 285 Obj: resp.Data, 286 } 287 case msg.Code == ReceiptsMsg: 288 p.Log().Trace("Received receipts response") 289 var resp struct { 290 ReqID, BV uint64 291 Receipts []types.Receipts 292 } 293 if err := msg.Decode(&resp); err != nil { 294 return errResp(ErrDecode, "msg %v: %v", msg, err) 295 } 296 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 297 p.answeredRequest(resp.ReqID) 298 deliverMsg = &Msg{ 299 MsgType: MsgReceipts, 300 ReqID: resp.ReqID, 301 Obj: resp.Receipts, 302 } 303 case msg.Code == ProofsV2Msg: 304 p.Log().Trace("Received les/2 proofs response") 305 var resp struct { 306 ReqID, BV uint64 307 Data light.NodeList 308 } 309 if err := msg.Decode(&resp); err != nil { 310 return errResp(ErrDecode, "msg %v: %v", msg, err) 311 } 312 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 313 p.answeredRequest(resp.ReqID) 314 deliverMsg = &Msg{ 315 MsgType: MsgProofsV2, 316 ReqID: resp.ReqID, 317 Obj: resp.Data, 318 } 319 case msg.Code == HelperTrieProofsMsg: 320 p.Log().Trace("Received helper trie proof response") 321 var resp struct { 322 ReqID, BV uint64 323 Data HelperTrieResps 324 } 325 if err := msg.Decode(&resp); err != nil { 326 return errResp(ErrDecode, "msg %v: %v", msg, err) 327 } 328 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 329 p.answeredRequest(resp.ReqID) 330 deliverMsg = &Msg{ 331 MsgType: MsgHelperTrieProofs, 332 ReqID: resp.ReqID, 333 Obj: resp.Data, 334 } 335 case msg.Code == TxStatusMsg: 336 p.Log().Trace("Received tx status response") 337 var resp struct { 338 ReqID, BV uint64 339 Status []light.TxStatus 340 } 341 if err := msg.Decode(&resp); err != nil { 342 return errResp(ErrDecode, "msg %v: %v", msg, err) 343 } 344 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 345 p.answeredRequest(resp.ReqID) 346 deliverMsg = &Msg{ 347 MsgType: MsgTxStatus, 348 ReqID: resp.ReqID, 349 Obj: resp.Status, 350 } 351 case msg.Code == StopMsg && p.version >= lpv3: 352 p.freeze() 353 h.backend.retriever.frozen(p) 354 p.Log().Debug("Service stopped") 355 case msg.Code == ResumeMsg && p.version >= lpv3: 356 var bv uint64 357 if err := msg.Decode(&bv); err != nil { 358 return errResp(ErrDecode, "msg %v: %v", msg, err) 359 } 360 p.fcServer.ResumeFreeze(bv) 361 p.unfreeze() 362 p.Log().Debug("Service resumed") 363 default: 364 p.Log().Trace("Received invalid message", "code", msg.Code) 365 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 366 } 367 // Deliver the received response to retriever. 368 if deliverMsg != nil { 369 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 370 if val := p.errCount.Add(1, mclock.Now()); val > maxResponseErrors { 371 return err 372 } 373 } 374 } 375 return nil 376 } 377 378 func (h *clientHandler) removePeer(id string) { 379 h.backend.peers.unregister(id) 380 } 381 382 type peerConnection struct { 383 handler *clientHandler 384 peer *serverPeer 385 } 386 387 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 388 return pc.peer.HeadAndTd() 389 } 390 391 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 392 rq := &distReq{ 393 getCost: func(dp distPeer) uint64 { 394 peer := dp.(*serverPeer) 395 return peer.getRequestCost(GetBlockHeadersMsg, amount) 396 }, 397 canSend: func(dp distPeer) bool { 398 return dp.(*serverPeer) == pc.peer 399 }, 400 request: func(dp distPeer) func() { 401 reqID := rand.Uint64() 402 peer := dp.(*serverPeer) 403 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 404 peer.fcServer.QueuedRequest(reqID, cost) 405 return func() { peer.requestHeadersByHash(reqID, origin, amount, skip, reverse) } 406 }, 407 } 408 _, ok := <-pc.handler.backend.reqDist.queue(rq) 409 if !ok { 410 return light.ErrNoPeers 411 } 412 return nil 413 } 414 415 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 416 rq := &distReq{ 417 getCost: func(dp distPeer) uint64 { 418 peer := dp.(*serverPeer) 419 return peer.getRequestCost(GetBlockHeadersMsg, amount) 420 }, 421 canSend: func(dp distPeer) bool { 422 return dp.(*serverPeer) == pc.peer 423 }, 424 request: func(dp distPeer) func() { 425 reqID := rand.Uint64() 426 peer := dp.(*serverPeer) 427 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 428 peer.fcServer.QueuedRequest(reqID, cost) 429 return func() { peer.requestHeadersByNumber(reqID, origin, amount, skip, reverse) } 430 }, 431 } 432 _, ok := <-pc.handler.backend.reqDist.queue(rq) 433 if !ok { 434 return light.ErrNoPeers 435 } 436 return nil 437 } 438 439 // RetrieveSingleHeaderByNumber requests a single header by the specified block 440 // number. This function will wait the response until it's timeout or delivered. 441 func (pc *peerConnection) RetrieveSingleHeaderByNumber(context context.Context, number uint64) (*types.Header, error) { 442 reqID := rand.Uint64() 443 rq := &distReq{ 444 getCost: func(dp distPeer) uint64 { 445 peer := dp.(*serverPeer) 446 return peer.getRequestCost(GetBlockHeadersMsg, 1) 447 }, 448 canSend: func(dp distPeer) bool { 449 return dp.(*serverPeer) == pc.peer 450 }, 451 request: func(dp distPeer) func() { 452 peer := dp.(*serverPeer) 453 cost := peer.getRequestCost(GetBlockHeadersMsg, 1) 454 peer.fcServer.QueuedRequest(reqID, cost) 455 return func() { peer.requestHeadersByNumber(reqID, number, 1, 0, false) } 456 }, 457 } 458 var header *types.Header 459 if err := pc.handler.backend.retriever.retrieve(context, reqID, rq, func(peer distPeer, msg *Msg) error { 460 if msg.MsgType != MsgBlockHeaders { 461 return errInvalidMessageType 462 } 463 headers := msg.Obj.([]*types.Header) 464 if len(headers) != 1 { 465 return errInvalidEntryCount 466 } 467 header = headers[0] 468 return nil 469 }, nil); err != nil { 470 return nil, err 471 } 472 return header, nil 473 } 474 475 // downloaderPeerNotify implements peerSetNotify 476 type downloaderPeerNotify clientHandler 477 478 func (d *downloaderPeerNotify) registerPeer(p *serverPeer) { 479 h := (*clientHandler)(d) 480 pc := &peerConnection{ 481 handler: h, 482 peer: p, 483 } 484 h.downloader.RegisterLightPeer(p.id, eth.ETH66, pc) 485 } 486 487 func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) { 488 h := (*clientHandler)(d) 489 h.downloader.UnregisterPeer(p.id) 490 }