github.com/Debrief-BC/go-debrief@v0.0.0-20200420203408-0c26ca968123/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/Debrief-BC/go-debrief/common" 26 "github.com/Debrief-BC/go-debrief/common/mclock" 27 "github.com/Debrief-BC/go-debrief/core/types" 28 "github.com/Debrief-BC/go-debrief/eth/downloader" 29 "github.com/Debrief-BC/go-debrief/light" 30 "github.com/Debrief-BC/go-debrief/log" 31 "github.com/Debrief-BC/go-debrief/p2p" 32 "github.com/Debrief-BC/go-debrief/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 184 if req.Hash != (common.Hash{}) { 185 if p.announceType == announceTypeNone { 186 return errResp(ErrUnexpectedResponse, "") 187 } 188 if p.announceType == announceTypeSigned { 189 if err := req.checkSignature(p.ID(), update); err != nil { 190 p.Log().Trace("Invalid announcement signature", "err", err) 191 return err 192 } 193 p.Log().Trace("Valid announcement signature") 194 } 195 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 196 h.fetcher.announce(p, &req) 197 } 198 case BlockHeadersMsg: 199 p.Log().Trace("Received block header response message") 200 var resp struct { 201 ReqID, BV uint64 202 Headers []*types.Header 203 } 204 if err := msg.Decode(&resp); err != nil { 205 return errResp(ErrDecode, "msg %v: %v", msg, err) 206 } 207 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 208 if h.fetcher.requestedID(resp.ReqID) { 209 h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 210 } else { 211 if err := h.downloader.DeliverHeaders(p.id, resp.Headers); err != nil { 212 log.Debug("Failed to deliver headers", "err", err) 213 } 214 } 215 case BlockBodiesMsg: 216 p.Log().Trace("Received block bodies response") 217 var resp struct { 218 ReqID, BV uint64 219 Data []*types.Body 220 } 221 if err := msg.Decode(&resp); err != nil { 222 return errResp(ErrDecode, "msg %v: %v", msg, err) 223 } 224 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 225 deliverMsg = &Msg{ 226 MsgType: MsgBlockBodies, 227 ReqID: resp.ReqID, 228 Obj: resp.Data, 229 } 230 case CodeMsg: 231 p.Log().Trace("Received code response") 232 var resp struct { 233 ReqID, BV uint64 234 Data [][]byte 235 } 236 if err := msg.Decode(&resp); err != nil { 237 return errResp(ErrDecode, "msg %v: %v", msg, err) 238 } 239 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 240 deliverMsg = &Msg{ 241 MsgType: MsgCode, 242 ReqID: resp.ReqID, 243 Obj: resp.Data, 244 } 245 case ReceiptsMsg: 246 p.Log().Trace("Received receipts response") 247 var resp struct { 248 ReqID, BV uint64 249 Receipts []types.Receipts 250 } 251 if err := msg.Decode(&resp); err != nil { 252 return errResp(ErrDecode, "msg %v: %v", msg, err) 253 } 254 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 255 deliverMsg = &Msg{ 256 MsgType: MsgReceipts, 257 ReqID: resp.ReqID, 258 Obj: resp.Receipts, 259 } 260 case ProofsV2Msg: 261 p.Log().Trace("Received les/2 proofs response") 262 var resp struct { 263 ReqID, BV uint64 264 Data light.NodeList 265 } 266 if err := msg.Decode(&resp); err != nil { 267 return errResp(ErrDecode, "msg %v: %v", msg, err) 268 } 269 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 270 deliverMsg = &Msg{ 271 MsgType: MsgProofsV2, 272 ReqID: resp.ReqID, 273 Obj: resp.Data, 274 } 275 case HelperTrieProofsMsg: 276 p.Log().Trace("Received helper trie proof response") 277 var resp struct { 278 ReqID, BV uint64 279 Data HelperTrieResps 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 deliverMsg = &Msg{ 286 MsgType: MsgHelperTrieProofs, 287 ReqID: resp.ReqID, 288 Obj: resp.Data, 289 } 290 case TxStatusMsg: 291 p.Log().Trace("Received tx status response") 292 var resp struct { 293 ReqID, BV uint64 294 Status []light.TxStatus 295 } 296 if err := msg.Decode(&resp); err != nil { 297 return errResp(ErrDecode, "msg %v: %v", msg, err) 298 } 299 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 300 deliverMsg = &Msg{ 301 MsgType: MsgTxStatus, 302 ReqID: resp.ReqID, 303 Obj: resp.Status, 304 } 305 case StopMsg: 306 p.freeze() 307 h.backend.retriever.frozen(p) 308 p.Log().Debug("Service stopped") 309 case ResumeMsg: 310 var bv uint64 311 if err := msg.Decode(&bv); err != nil { 312 return errResp(ErrDecode, "msg %v: %v", msg, err) 313 } 314 p.fcServer.ResumeFreeze(bv) 315 p.unfreeze() 316 p.Log().Debug("Service resumed") 317 default: 318 p.Log().Trace("Received invalid message", "code", msg.Code) 319 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 320 } 321 // Deliver the received response to retriever. 322 if deliverMsg != nil { 323 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 324 p.errCount++ 325 if p.errCount > maxResponseErrors { 326 return err 327 } 328 } 329 } 330 return nil 331 } 332 333 func (h *clientHandler) removePeer(id string) { 334 h.backend.peers.unregister(id) 335 } 336 337 type peerConnection struct { 338 handler *clientHandler 339 peer *serverPeer 340 } 341 342 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 343 return pc.peer.HeadAndTd() 344 } 345 346 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 347 rq := &distReq{ 348 getCost: func(dp distPeer) uint64 { 349 peer := dp.(*serverPeer) 350 return peer.getRequestCost(GetBlockHeadersMsg, amount) 351 }, 352 canSend: func(dp distPeer) bool { 353 return dp.(*serverPeer) == pc.peer 354 }, 355 request: func(dp distPeer) func() { 356 reqID := genReqID() 357 peer := dp.(*serverPeer) 358 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 359 peer.fcServer.QueuedRequest(reqID, cost) 360 return func() { peer.requestHeadersByHash(reqID, origin, amount, skip, reverse) } 361 }, 362 } 363 _, ok := <-pc.handler.backend.reqDist.queue(rq) 364 if !ok { 365 return light.ErrNoPeers 366 } 367 return nil 368 } 369 370 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 371 rq := &distReq{ 372 getCost: func(dp distPeer) uint64 { 373 peer := dp.(*serverPeer) 374 return peer.getRequestCost(GetBlockHeadersMsg, amount) 375 }, 376 canSend: func(dp distPeer) bool { 377 return dp.(*serverPeer) == pc.peer 378 }, 379 request: func(dp distPeer) func() { 380 reqID := genReqID() 381 peer := dp.(*serverPeer) 382 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 383 peer.fcServer.QueuedRequest(reqID, cost) 384 return func() { peer.requestHeadersByNumber(reqID, origin, amount, skip, reverse) } 385 }, 386 } 387 _, ok := <-pc.handler.backend.reqDist.queue(rq) 388 if !ok { 389 return light.ErrNoPeers 390 } 391 return nil 392 } 393 394 // downloaderPeerNotify implements peerSetNotify 395 type downloaderPeerNotify clientHandler 396 397 func (d *downloaderPeerNotify) registerPeer(p *serverPeer) { 398 h := (*clientHandler)(d) 399 pc := &peerConnection{ 400 handler: h, 401 peer: p, 402 } 403 h.downloader.RegisterLightPeer(p.id, ethVersion, pc) 404 } 405 406 func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) { 407 h := (*clientHandler)(d) 408 h.downloader.UnregisterPeer(p.id) 409 }