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