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