github.com/JFJun/bsc@v1.0.0/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/JFJun/bsc/common" 26 "github.com/JFJun/bsc/common/mclock" 27 "github.com/JFJun/bsc/core/types" 28 "github.com/JFJun/bsc/eth/downloader" 29 "github.com/JFJun/bsc/light" 30 "github.com/JFJun/bsc/log" 31 "github.com/JFJun/bsc/p2p" 32 "github.com/JFJun/bsc/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) 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 peer.poolEntry = h.backend.serverPool.connect(peer, peer.Node()) 89 if peer.poolEntry == nil { 90 return p2p.DiscRequested 91 } 92 h.wg.Add(1) 93 defer h.wg.Done() 94 err := h.handle(peer) 95 h.backend.serverPool.disconnect(peer.poolEntry) 96 return err 97 } 98 99 func (h *clientHandler) handle(p *serverPeer) error { 100 if h.backend.peers.len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted { 101 return p2p.DiscTooManyPeers 102 } 103 p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) 104 105 // Execute the LES handshake 106 var ( 107 head = h.backend.blockchain.CurrentHeader() 108 hash = head.Hash() 109 number = head.Number.Uint64() 110 td = h.backend.blockchain.GetTd(hash, number) 111 ) 112 if err := p.Handshake(td, hash, number, h.backend.blockchain.Genesis().Hash(), nil); err != nil { 113 p.Log().Debug("Light Ethereum handshake failed", "err", err) 114 return err 115 } 116 // Register the peer locally 117 if err := h.backend.peers.register(p); err != nil { 118 p.Log().Error("Light Ethereum peer registration failed", "err", err) 119 return err 120 } 121 serverConnectionGauge.Update(int64(h.backend.peers.len())) 122 123 connectedAt := mclock.Now() 124 defer func() { 125 h.backend.peers.unregister(p.id) 126 connectionTimer.Update(time.Duration(mclock.Now() - connectedAt)) 127 serverConnectionGauge.Update(int64(h.backend.peers.len())) 128 }() 129 130 h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td}) 131 132 // pool entry can be nil during the unit test. 133 if p.poolEntry != nil { 134 h.backend.serverPool.registered(p.poolEntry) 135 } 136 // Mark the peer starts to be served. 137 atomic.StoreUint32(&p.serving, 1) 138 defer atomic.StoreUint32(&p.serving, 0) 139 140 // Spawn a main loop to handle all incoming messages. 141 for { 142 if err := h.handleMsg(p); err != nil { 143 p.Log().Debug("Light Ethereum message handling failed", "err", err) 144 p.fcServer.DumpLogs() 145 return err 146 } 147 } 148 } 149 150 // handleMsg is invoked whenever an inbound message is received from a remote 151 // peer. The remote connection is torn down upon returning any error. 152 func (h *clientHandler) handleMsg(p *serverPeer) error { 153 // Read the next message from the remote peer, and ensure it's fully consumed 154 msg, err := p.rw.ReadMsg() 155 if err != nil { 156 return err 157 } 158 p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size) 159 160 if msg.Size > ProtocolMaxMsgSize { 161 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 162 } 163 defer msg.Discard() 164 165 var deliverMsg *Msg 166 167 // Handle the message depending on its contents 168 switch msg.Code { 169 case AnnounceMsg: 170 p.Log().Trace("Received announce message") 171 var req announceData 172 if err := msg.Decode(&req); err != nil { 173 return errResp(ErrDecode, "%v: %v", msg, err) 174 } 175 if err := req.sanityCheck(); err != nil { 176 return err 177 } 178 update, size := req.Update.decode() 179 if p.rejectUpdate(size) { 180 return errResp(ErrRequestRejected, "") 181 } 182 p.updateFlowControl(update) 183 p.updateVtParams() 184 185 if req.Hash != (common.Hash{}) { 186 if p.announceType == announceTypeNone { 187 return errResp(ErrUnexpectedResponse, "") 188 } 189 if p.announceType == announceTypeSigned { 190 if err := req.checkSignature(p.ID(), update); err != nil { 191 p.Log().Trace("Invalid announcement signature", "err", err) 192 return err 193 } 194 p.Log().Trace("Valid announcement signature") 195 } 196 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 197 h.fetcher.announce(p, &req) 198 } 199 case BlockHeadersMsg: 200 p.Log().Trace("Received block header response message") 201 var resp struct { 202 ReqID, BV uint64 203 Headers []*types.Header 204 } 205 if err := msg.Decode(&resp); err != nil { 206 return errResp(ErrDecode, "msg %v: %v", msg, err) 207 } 208 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 209 p.answeredRequest(resp.ReqID) 210 if h.fetcher.requestedID(resp.ReqID) { 211 h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 212 } else { 213 if err := h.downloader.DeliverHeaders(p.id, resp.Headers); err != nil { 214 log.Debug("Failed to deliver headers", "err", err) 215 } 216 } 217 case BlockBodiesMsg: 218 p.Log().Trace("Received block bodies response") 219 var resp struct { 220 ReqID, BV uint64 221 Data []*types.Body 222 } 223 if err := msg.Decode(&resp); err != nil { 224 return errResp(ErrDecode, "msg %v: %v", msg, err) 225 } 226 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 227 p.answeredRequest(resp.ReqID) 228 deliverMsg = &Msg{ 229 MsgType: MsgBlockBodies, 230 ReqID: resp.ReqID, 231 Obj: resp.Data, 232 } 233 case CodeMsg: 234 p.Log().Trace("Received code response") 235 var resp struct { 236 ReqID, BV uint64 237 Data [][]byte 238 } 239 if err := msg.Decode(&resp); err != nil { 240 return errResp(ErrDecode, "msg %v: %v", msg, err) 241 } 242 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 243 p.answeredRequest(resp.ReqID) 244 deliverMsg = &Msg{ 245 MsgType: MsgCode, 246 ReqID: resp.ReqID, 247 Obj: resp.Data, 248 } 249 case ReceiptsMsg: 250 p.Log().Trace("Received receipts response") 251 var resp struct { 252 ReqID, BV uint64 253 Receipts []types.Receipts 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: MsgReceipts, 262 ReqID: resp.ReqID, 263 Obj: resp.Receipts, 264 } 265 case ProofsV2Msg: 266 p.Log().Trace("Received les/2 proofs response") 267 var resp struct { 268 ReqID, BV uint64 269 Data light.NodeList 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: MsgProofsV2, 278 ReqID: resp.ReqID, 279 Obj: resp.Data, 280 } 281 case HelperTrieProofsMsg: 282 p.Log().Trace("Received helper trie proof response") 283 var resp struct { 284 ReqID, BV uint64 285 Data HelperTrieResps 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: MsgHelperTrieProofs, 294 ReqID: resp.ReqID, 295 Obj: resp.Data, 296 } 297 case TxStatusMsg: 298 p.Log().Trace("Received tx status response") 299 var resp struct { 300 ReqID, BV uint64 301 Status []light.TxStatus 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: MsgTxStatus, 310 ReqID: resp.ReqID, 311 Obj: resp.Status, 312 } 313 case StopMsg: 314 p.freeze() 315 h.backend.retriever.frozen(p) 316 p.Log().Debug("Service stopped") 317 case ResumeMsg: 318 var bv uint64 319 if err := msg.Decode(&bv); err != nil { 320 return errResp(ErrDecode, "msg %v: %v", msg, err) 321 } 322 p.fcServer.ResumeFreeze(bv) 323 p.unfreeze() 324 p.Log().Debug("Service resumed") 325 default: 326 p.Log().Trace("Received invalid message", "code", msg.Code) 327 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 328 } 329 // Deliver the received response to retriever. 330 if deliverMsg != nil { 331 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 332 p.errCount++ 333 if p.errCount > maxResponseErrors { 334 return err 335 } 336 } 337 } 338 return nil 339 } 340 341 func (h *clientHandler) removePeer(id string) { 342 h.backend.peers.unregister(id) 343 } 344 345 type peerConnection struct { 346 handler *clientHandler 347 peer *serverPeer 348 } 349 350 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 351 return pc.peer.HeadAndTd() 352 } 353 354 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 355 rq := &distReq{ 356 getCost: func(dp distPeer) uint64 { 357 peer := dp.(*serverPeer) 358 return peer.getRequestCost(GetBlockHeadersMsg, amount) 359 }, 360 canSend: func(dp distPeer) bool { 361 return dp.(*serverPeer) == pc.peer 362 }, 363 request: func(dp distPeer) func() { 364 reqID := genReqID() 365 peer := dp.(*serverPeer) 366 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 367 peer.fcServer.QueuedRequest(reqID, cost) 368 return func() { peer.requestHeadersByHash(reqID, origin, amount, skip, reverse) } 369 }, 370 } 371 _, ok := <-pc.handler.backend.reqDist.queue(rq) 372 if !ok { 373 return light.ErrNoPeers 374 } 375 return nil 376 } 377 378 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 379 rq := &distReq{ 380 getCost: func(dp distPeer) uint64 { 381 peer := dp.(*serverPeer) 382 return peer.getRequestCost(GetBlockHeadersMsg, amount) 383 }, 384 canSend: func(dp distPeer) bool { 385 return dp.(*serverPeer) == pc.peer 386 }, 387 request: func(dp distPeer) func() { 388 reqID := genReqID() 389 peer := dp.(*serverPeer) 390 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 391 peer.fcServer.QueuedRequest(reqID, cost) 392 return func() { peer.requestHeadersByNumber(reqID, origin, amount, skip, reverse) } 393 }, 394 } 395 _, ok := <-pc.handler.backend.reqDist.queue(rq) 396 if !ok { 397 return light.ErrNoPeers 398 } 399 return nil 400 } 401 402 // downloaderPeerNotify implements peerSetNotify 403 type downloaderPeerNotify clientHandler 404 405 func (d *downloaderPeerNotify) registerPeer(p *serverPeer) { 406 h := (*clientHandler)(d) 407 pc := &peerConnection{ 408 handler: h, 409 peer: p, 410 } 411 h.downloader.RegisterLightPeer(p.id, ethVersion, pc) 412 } 413 414 func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) { 415 h := (*clientHandler)(d) 416 h.downloader.UnregisterPeer(p.id) 417 }