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