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