github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/les/client_handler.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 package les 18 19 import ( 20 "math/big" 21 "sync" 22 "time" 23 24 "github.com/ebakus/go-ebakus/common" 25 "github.com/ebakus/go-ebakus/common/mclock" 26 "github.com/ebakus/go-ebakus/core/types" 27 "github.com/ebakus/go-ebakus/eth/downloader" 28 "github.com/ebakus/go-ebakus/light" 29 "github.com/ebakus/go-ebakus/log" 30 "github.com/ebakus/go-ebakus/p2p" 31 "github.com/ebakus/go-ebakus/params" 32 ) 33 34 // clientHandler is responsible for receiving and processing all incoming server 35 // responses. 36 type clientHandler struct { 37 ulc *ulc 38 checkpoint *params.TrustedCheckpoint 39 fetcher *lightFetcher 40 downloader *downloader.Downloader 41 backend *LightEbakus 42 43 closeCh chan struct{} 44 wg sync.WaitGroup // WaitGroup used to track all connected peers. 45 syncDone func() // Test hooks when syncing is done. 46 } 47 48 func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEbakus) *clientHandler { 49 handler := &clientHandler{ 50 checkpoint: checkpoint, 51 backend: backend, 52 closeCh: make(chan struct{}), 53 } 54 if ulcServers != nil { 55 ulc, err := newULC(ulcServers, ulcFraction) 56 if err != nil { 57 log.Error("Failed to initialize ultra light client") 58 } 59 handler.ulc = ulc 60 log.Info("Enable ultra light client mode") 61 } 62 var height uint64 63 if checkpoint != nil { 64 height = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1 65 } 66 handler.fetcher = newLightFetcher(handler) 67 handler.downloader = downloader.New(height, backend.chainDb, nil, backend.eventMux, nil, backend.blockchain, handler.removePeer) 68 handler.backend.peers.notify((*downloaderPeerNotify)(handler)) 69 return handler 70 } 71 72 func (h *clientHandler) stop() { 73 close(h.closeCh) 74 h.downloader.Terminate() 75 h.fetcher.close() 76 h.wg.Wait() 77 } 78 79 // runPeer is the p2p protocol run function for the given version. 80 func (h *clientHandler) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error { 81 trusted := false 82 if h.ulc != nil { 83 trusted = h.ulc.trusted(p.ID()) 84 } 85 peer := newPeer(int(version), h.backend.config.NetworkId, trusted, p, newMeteredMsgWriter(rw, int(version))) 86 peer.poolEntry = h.backend.serverPool.connect(peer, peer.Node()) 87 if peer.poolEntry == nil { 88 return p2p.DiscRequested 89 } 90 h.wg.Add(1) 91 defer h.wg.Done() 92 err := h.handle(peer) 93 h.backend.serverPool.disconnect(peer.poolEntry) 94 return err 95 } 96 97 func (h *clientHandler) handle(p *peer) error { 98 if h.backend.peers.Len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted { 99 return p2p.DiscTooManyPeers 100 } 101 p.Log().Debug("Light Ebakus peer connected", "name", p.Name()) 102 103 // Execute the LES handshake 104 var ( 105 head = h.backend.blockchain.CurrentHeader() 106 hash = head.Hash() 107 number = head.Number.Uint64() 108 ) 109 if err := p.Handshake(big.NewInt(int64(number)), hash, number, h.backend.blockchain.Genesis().Hash(), nil); err != nil { 110 p.Log().Debug("Light Ebakus handshake failed", "err", err) 111 return err 112 } 113 // Register the peer locally 114 if err := h.backend.peers.Register(p); err != nil { 115 p.Log().Error("Light Ebakus peer registration failed", "err", err) 116 return err 117 } 118 serverConnectionGauge.Update(int64(h.backend.peers.Len())) 119 120 connectedAt := mclock.Now() 121 defer func() { 122 h.backend.peers.Unregister(p.id) 123 connectionTimer.Update(time.Duration(mclock.Now() - connectedAt)) 124 serverConnectionGauge.Update(int64(h.backend.peers.Len())) 125 }() 126 127 h.fetcher.announce(p, p.headInfo) 128 129 // pool entry can be nil during the unit test. 130 if p.poolEntry != nil { 131 h.backend.serverPool.registered(p.poolEntry) 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 Ebakus 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 *peer) 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 Ebakus 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 msg.Code { 162 case 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 177 if req.Hash != (common.Hash{}) { 178 if p.announceType == announceTypeNone { 179 return errResp(ErrUnexpectedResponse, "") 180 } 181 if p.announceType == announceTypeSigned { 182 if err := req.checkSignature(p.ID(), update); err != nil { 183 p.Log().Trace("Invalid announcement signature", "err", err) 184 return err 185 } 186 p.Log().Trace("Valid announcement signature") 187 } 188 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "reorg", req.ReorgDepth) 189 h.fetcher.announce(p, &req) 190 } 191 case BlockHeadersMsg: 192 p.Log().Trace("Received block header response message") 193 var resp struct { 194 ReqID, BV uint64 195 Headers []*types.Header 196 } 197 if err := msg.Decode(&resp); err != nil { 198 return errResp(ErrDecode, "msg %v: %v", msg, err) 199 } 200 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 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 deliverMsg = &Msg{ 219 MsgType: MsgBlockBodies, 220 ReqID: resp.ReqID, 221 Obj: resp.Data, 222 } 223 case CodeMsg: 224 p.Log().Trace("Received code response") 225 var resp struct { 226 ReqID, BV uint64 227 Data [][]byte 228 } 229 if err := msg.Decode(&resp); err != nil { 230 return errResp(ErrDecode, "msg %v: %v", msg, err) 231 } 232 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 233 deliverMsg = &Msg{ 234 MsgType: MsgCode, 235 ReqID: resp.ReqID, 236 Obj: resp.Data, 237 } 238 case ReceiptsMsg: 239 p.Log().Trace("Received receipts response") 240 var resp struct { 241 ReqID, BV uint64 242 Receipts []types.Receipts 243 } 244 if err := msg.Decode(&resp); err != nil { 245 return errResp(ErrDecode, "msg %v: %v", msg, err) 246 } 247 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 248 deliverMsg = &Msg{ 249 MsgType: MsgReceipts, 250 ReqID: resp.ReqID, 251 Obj: resp.Receipts, 252 } 253 case ProofsV2Msg: 254 p.Log().Trace("Received les/2 proofs response") 255 var resp struct { 256 ReqID, BV uint64 257 Data light.NodeList 258 } 259 if err := msg.Decode(&resp); err != nil { 260 return errResp(ErrDecode, "msg %v: %v", msg, err) 261 } 262 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 263 deliverMsg = &Msg{ 264 MsgType: MsgProofsV2, 265 ReqID: resp.ReqID, 266 Obj: resp.Data, 267 } 268 case HelperTrieProofsMsg: 269 p.Log().Trace("Received helper trie proof response") 270 var resp struct { 271 ReqID, BV uint64 272 Data HelperTrieResps 273 } 274 if err := msg.Decode(&resp); err != nil { 275 return errResp(ErrDecode, "msg %v: %v", msg, err) 276 } 277 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 278 deliverMsg = &Msg{ 279 MsgType: MsgHelperTrieProofs, 280 ReqID: resp.ReqID, 281 Obj: resp.Data, 282 } 283 case TxStatusMsg: 284 p.Log().Trace("Received tx status response") 285 var resp struct { 286 ReqID, BV uint64 287 Status []light.TxStatus 288 } 289 if err := msg.Decode(&resp); err != nil { 290 return errResp(ErrDecode, "msg %v: %v", msg, err) 291 } 292 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 293 deliverMsg = &Msg{ 294 MsgType: MsgTxStatus, 295 ReqID: resp.ReqID, 296 Obj: resp.Status, 297 } 298 case StopMsg: 299 p.freezeServer(true) 300 h.backend.retriever.frozen(p) 301 p.Log().Debug("Service stopped") 302 case ResumeMsg: 303 var bv uint64 304 if err := msg.Decode(&bv); err != nil { 305 return errResp(ErrDecode, "msg %v: %v", msg, err) 306 } 307 p.fcServer.ResumeFreeze(bv) 308 p.freezeServer(false) 309 p.Log().Debug("Service resumed") 310 default: 311 p.Log().Trace("Received invalid message", "code", msg.Code) 312 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 313 } 314 // Deliver the received response to retriever. 315 if deliverMsg != nil { 316 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 317 p.responseErrors++ 318 if p.responseErrors > maxResponseErrors { 319 return err 320 } 321 } 322 } 323 return nil 324 } 325 326 func (h *clientHandler) removePeer(id string) { 327 h.backend.peers.Unregister(id) 328 } 329 330 type peerConnection struct { 331 handler *clientHandler 332 peer *peer 333 } 334 335 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 336 return pc.peer.HeadAndTd() 337 } 338 339 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 340 rq := &distReq{ 341 getCost: func(dp distPeer) uint64 { 342 peer := dp.(*peer) 343 return peer.GetRequestCost(GetBlockHeadersMsg, amount) 344 }, 345 canSend: func(dp distPeer) bool { 346 return dp.(*peer) == pc.peer 347 }, 348 request: func(dp distPeer) func() { 349 reqID := genReqID() 350 peer := dp.(*peer) 351 cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) 352 peer.fcServer.QueuedRequest(reqID, cost) 353 return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) } 354 }, 355 } 356 _, ok := <-pc.handler.backend.reqDist.queue(rq) 357 if !ok { 358 return light.ErrNoPeers 359 } 360 return nil 361 } 362 363 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 364 rq := &distReq{ 365 getCost: func(dp distPeer) uint64 { 366 peer := dp.(*peer) 367 return peer.GetRequestCost(GetBlockHeadersMsg, amount) 368 }, 369 canSend: func(dp distPeer) bool { 370 return dp.(*peer) == pc.peer 371 }, 372 request: func(dp distPeer) func() { 373 reqID := genReqID() 374 peer := dp.(*peer) 375 cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) 376 peer.fcServer.QueuedRequest(reqID, cost) 377 return func() { peer.RequestHeadersByNumber(reqID, cost, 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 // downloaderPeerNotify implements peerSetNotify 388 type downloaderPeerNotify clientHandler 389 390 func (d *downloaderPeerNotify) registerPeer(p *peer) { 391 h := (*clientHandler)(d) 392 pc := &peerConnection{ 393 handler: h, 394 peer: p, 395 } 396 h.downloader.RegisterLightPeer(p.id, ethVersion, pc) 397 } 398 399 func (d *downloaderPeerNotify) unregisterPeer(p *peer) { 400 h := (*clientHandler)(d) 401 h.downloader.UnregisterPeer(p.id) 402 }