github.com/c2s/go-ethereum@v1.9.7/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 syncDone func() // Test hooks when syncing is done. 46 } 47 48 func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEthereum) *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 Ethereum 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 td = h.backend.blockchain.GetTd(hash, number) 109 ) 110 if err := p.Handshake(td, hash, number, h.backend.blockchain.Genesis().Hash(), nil); err != nil { 111 p.Log().Debug("Light Ethereum handshake failed", "err", err) 112 return err 113 } 114 // Register the peer locally 115 if err := h.backend.peers.Register(p); err != nil { 116 p.Log().Error("Light Ethereum peer registration failed", "err", err) 117 return err 118 } 119 serverConnectionGauge.Update(int64(h.backend.peers.Len())) 120 121 connectedAt := mclock.Now() 122 defer func() { 123 h.backend.peers.Unregister(p.id) 124 connectionTimer.Update(time.Duration(mclock.Now() - connectedAt)) 125 serverConnectionGauge.Update(int64(h.backend.peers.Len())) 126 }() 127 128 h.fetcher.announce(p, p.headInfo) 129 130 // pool entry can be nil during the unit test. 131 if p.poolEntry != nil { 132 h.backend.serverPool.registered(p.poolEntry) 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 *peer) 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 178 if req.Hash != (common.Hash{}) { 179 if p.announceType == announceTypeNone { 180 return errResp(ErrUnexpectedResponse, "") 181 } 182 if p.announceType == announceTypeSigned { 183 if err := req.checkSignature(p.ID(), update); err != nil { 184 p.Log().Trace("Invalid announcement signature", "err", err) 185 return err 186 } 187 p.Log().Trace("Valid announcement signature") 188 } 189 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 190 h.fetcher.announce(p, &req) 191 } 192 case BlockHeadersMsg: 193 p.Log().Trace("Received block header response message") 194 var resp struct { 195 ReqID, BV uint64 196 Headers []*types.Header 197 } 198 if err := msg.Decode(&resp); err != nil { 199 return errResp(ErrDecode, "msg %v: %v", msg, err) 200 } 201 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 202 if h.fetcher.requestedID(resp.ReqID) { 203 h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 204 } else { 205 if err := h.downloader.DeliverHeaders(p.id, resp.Headers); err != nil { 206 log.Debug("Failed to deliver headers", "err", err) 207 } 208 } 209 case BlockBodiesMsg: 210 p.Log().Trace("Received block bodies response") 211 var resp struct { 212 ReqID, BV uint64 213 Data []*types.Body 214 } 215 if err := msg.Decode(&resp); err != nil { 216 return errResp(ErrDecode, "msg %v: %v", msg, err) 217 } 218 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 219 deliverMsg = &Msg{ 220 MsgType: MsgBlockBodies, 221 ReqID: resp.ReqID, 222 Obj: resp.Data, 223 } 224 case CodeMsg: 225 p.Log().Trace("Received code response") 226 var resp struct { 227 ReqID, BV uint64 228 Data [][]byte 229 } 230 if err := msg.Decode(&resp); err != nil { 231 return errResp(ErrDecode, "msg %v: %v", msg, err) 232 } 233 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 234 deliverMsg = &Msg{ 235 MsgType: MsgCode, 236 ReqID: resp.ReqID, 237 Obj: resp.Data, 238 } 239 case ReceiptsMsg: 240 p.Log().Trace("Received receipts response") 241 var resp struct { 242 ReqID, BV uint64 243 Receipts []types.Receipts 244 } 245 if err := msg.Decode(&resp); err != nil { 246 return errResp(ErrDecode, "msg %v: %v", msg, err) 247 } 248 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 249 deliverMsg = &Msg{ 250 MsgType: MsgReceipts, 251 ReqID: resp.ReqID, 252 Obj: resp.Receipts, 253 } 254 case ProofsV2Msg: 255 p.Log().Trace("Received les/2 proofs response") 256 var resp struct { 257 ReqID, BV uint64 258 Data light.NodeList 259 } 260 if err := msg.Decode(&resp); err != nil { 261 return errResp(ErrDecode, "msg %v: %v", msg, err) 262 } 263 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 264 deliverMsg = &Msg{ 265 MsgType: MsgProofsV2, 266 ReqID: resp.ReqID, 267 Obj: resp.Data, 268 } 269 case HelperTrieProofsMsg: 270 p.Log().Trace("Received helper trie proof response") 271 var resp struct { 272 ReqID, BV uint64 273 Data HelperTrieResps 274 } 275 if err := msg.Decode(&resp); err != nil { 276 return errResp(ErrDecode, "msg %v: %v", msg, err) 277 } 278 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 279 deliverMsg = &Msg{ 280 MsgType: MsgHelperTrieProofs, 281 ReqID: resp.ReqID, 282 Obj: resp.Data, 283 } 284 case TxStatusMsg: 285 p.Log().Trace("Received tx status response") 286 var resp struct { 287 ReqID, BV uint64 288 Status []light.TxStatus 289 } 290 if err := msg.Decode(&resp); err != nil { 291 return errResp(ErrDecode, "msg %v: %v", msg, err) 292 } 293 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 294 deliverMsg = &Msg{ 295 MsgType: MsgTxStatus, 296 ReqID: resp.ReqID, 297 Obj: resp.Status, 298 } 299 case StopMsg: 300 p.freezeServer(true) 301 h.backend.retriever.frozen(p) 302 p.Log().Debug("Service stopped") 303 case ResumeMsg: 304 var bv uint64 305 if err := msg.Decode(&bv); err != nil { 306 return errResp(ErrDecode, "msg %v: %v", msg, err) 307 } 308 p.fcServer.ResumeFreeze(bv) 309 p.freezeServer(false) 310 p.Log().Debug("Service resumed") 311 default: 312 p.Log().Trace("Received invalid message", "code", msg.Code) 313 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 314 } 315 // Deliver the received response to retriever. 316 if deliverMsg != nil { 317 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 318 p.responseErrors++ 319 if p.responseErrors > maxResponseErrors { 320 return err 321 } 322 } 323 } 324 return nil 325 } 326 327 func (h *clientHandler) removePeer(id string) { 328 h.backend.peers.Unregister(id) 329 } 330 331 type peerConnection struct { 332 handler *clientHandler 333 peer *peer 334 } 335 336 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 337 return pc.peer.HeadAndTd() 338 } 339 340 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 341 rq := &distReq{ 342 getCost: func(dp distPeer) uint64 { 343 peer := dp.(*peer) 344 return peer.GetRequestCost(GetBlockHeadersMsg, amount) 345 }, 346 canSend: func(dp distPeer) bool { 347 return dp.(*peer) == pc.peer 348 }, 349 request: func(dp distPeer) func() { 350 reqID := genReqID() 351 peer := dp.(*peer) 352 cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) 353 peer.fcServer.QueuedRequest(reqID, cost) 354 return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) } 355 }, 356 } 357 _, ok := <-pc.handler.backend.reqDist.queue(rq) 358 if !ok { 359 return light.ErrNoPeers 360 } 361 return nil 362 } 363 364 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 365 rq := &distReq{ 366 getCost: func(dp distPeer) uint64 { 367 peer := dp.(*peer) 368 return peer.GetRequestCost(GetBlockHeadersMsg, amount) 369 }, 370 canSend: func(dp distPeer) bool { 371 return dp.(*peer) == pc.peer 372 }, 373 request: func(dp distPeer) func() { 374 reqID := genReqID() 375 peer := dp.(*peer) 376 cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) 377 peer.fcServer.QueuedRequest(reqID, cost) 378 return func() { peer.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) } 379 }, 380 } 381 _, ok := <-pc.handler.backend.reqDist.queue(rq) 382 if !ok { 383 return light.ErrNoPeers 384 } 385 return nil 386 } 387 388 // downloaderPeerNotify implements peerSetNotify 389 type downloaderPeerNotify clientHandler 390 391 func (d *downloaderPeerNotify) registerPeer(p *peer) { 392 h := (*clientHandler)(d) 393 pc := &peerConnection{ 394 handler: h, 395 peer: p, 396 } 397 h.downloader.RegisterLightPeer(p.id, ethVersion, pc) 398 } 399 400 func (d *downloaderPeerNotify) unregisterPeer(p *peer) { 401 h := (*clientHandler)(d) 402 h.downloader.UnregisterPeer(p.id) 403 }