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