github.com/cryptogateway/go-paymex@v0.0.0-20210204174735-96277fb1e602/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 "context" 21 "math/big" 22 "sync" 23 "sync/atomic" 24 "time" 25 26 "github.com/cryptogateway/go-paymex/common" 27 "github.com/cryptogateway/go-paymex/common/mclock" 28 "github.com/cryptogateway/go-paymex/core/forkid" 29 "github.com/cryptogateway/go-paymex/core/types" 30 "github.com/cryptogateway/go-paymex/eth/downloader" 31 "github.com/cryptogateway/go-paymex/light" 32 "github.com/cryptogateway/go-paymex/log" 33 "github.com/cryptogateway/go-paymex/p2p" 34 "github.com/cryptogateway/go-paymex/params" 35 ) 36 37 // clientHandler is responsible for receiving and processing all incoming server 38 // responses. 39 type clientHandler struct { 40 ulc *ulc 41 forkFilter forkid.Filter 42 checkpoint *params.TrustedCheckpoint 43 fetcher *lightFetcher 44 downloader *downloader.Downloader 45 backend *LightEthereum 46 47 closeCh chan struct{} 48 wg sync.WaitGroup // WaitGroup used to track all connected peers. 49 50 // Hooks used in the testing 51 syncStart func(header *types.Header) // Hook called when the syncing is started 52 syncEnd func(header *types.Header) // Hook called when the syncing is done 53 } 54 55 func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEthereum) *clientHandler { 56 handler := &clientHandler{ 57 forkFilter: forkid.NewFilter(backend.blockchain), 58 checkpoint: checkpoint, 59 backend: backend, 60 closeCh: make(chan struct{}), 61 } 62 if ulcServers != nil { 63 ulc, err := newULC(ulcServers, ulcFraction) 64 if err != nil { 65 log.Error("Failed to initialize ultra light client") 66 } 67 handler.ulc = ulc 68 log.Info("Enable ultra light client mode") 69 } 70 var height uint64 71 if checkpoint != nil { 72 height = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1 73 } 74 handler.fetcher = newLightFetcher(backend.blockchain, backend.engine, backend.peers, handler.ulc, backend.chainDb, backend.reqDist, handler.synchronise) 75 handler.downloader = downloader.New(height, backend.chainDb, nil, backend.eventMux, nil, backend.blockchain, handler.removePeer) 76 handler.backend.peers.subscribe((*downloaderPeerNotify)(handler)) 77 return handler 78 } 79 80 func (h *clientHandler) start() { 81 h.fetcher.start() 82 } 83 84 func (h *clientHandler) stop() { 85 close(h.closeCh) 86 h.downloader.Terminate() 87 h.fetcher.stop() 88 h.wg.Wait() 89 } 90 91 // runPeer is the p2p protocol run function for the given version. 92 func (h *clientHandler) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error { 93 trusted := false 94 if h.ulc != nil { 95 trusted = h.ulc.trusted(p.ID()) 96 } 97 peer := newServerPeer(int(version), h.backend.config.NetworkId, trusted, p, newMeteredMsgWriter(rw, int(version))) 98 defer peer.close() 99 h.wg.Add(1) 100 defer h.wg.Done() 101 err := h.handle(peer) 102 return err 103 } 104 105 func (h *clientHandler) handle(p *serverPeer) error { 106 if h.backend.peers.len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted { 107 return p2p.DiscTooManyPeers 108 } 109 p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) 110 111 // Execute the LES handshake 112 forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64()) 113 if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil { 114 p.Log().Debug("Light Ethereum handshake failed", "err", err) 115 return err 116 } 117 // Register the peer locally 118 if err := h.backend.peers.register(p); err != nil { 119 p.Log().Error("Light Ethereum peer registration failed", "err", err) 120 return err 121 } 122 serverConnectionGauge.Update(int64(h.backend.peers.len())) 123 124 connectedAt := mclock.Now() 125 defer func() { 126 h.backend.peers.unregister(p.id) 127 connectionTimer.Update(time.Duration(mclock.Now() - connectedAt)) 128 serverConnectionGauge.Update(int64(h.backend.peers.len())) 129 }() 130 h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td}) 131 132 // Mark the peer starts to be served. 133 atomic.StoreUint32(&p.serving, 1) 134 defer atomic.StoreUint32(&p.serving, 0) 135 136 // Spawn a main loop to handle all incoming messages. 137 for { 138 if err := h.handleMsg(p); err != nil { 139 p.Log().Debug("Light Ethereum message handling failed", "err", err) 140 p.fcServer.DumpLogs() 141 return err 142 } 143 } 144 } 145 146 // handleMsg is invoked whenever an inbound message is received from a remote 147 // peer. The remote connection is torn down upon returning any error. 148 func (h *clientHandler) handleMsg(p *serverPeer) error { 149 // Read the next message from the remote peer, and ensure it's fully consumed 150 msg, err := p.rw.ReadMsg() 151 if err != nil { 152 return err 153 } 154 p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size) 155 156 if msg.Size > ProtocolMaxMsgSize { 157 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 158 } 159 defer msg.Discard() 160 161 var deliverMsg *Msg 162 163 // Handle the message depending on its contents 164 switch { 165 case msg.Code == AnnounceMsg: 166 p.Log().Trace("Received announce message") 167 var req announceData 168 if err := msg.Decode(&req); err != nil { 169 return errResp(ErrDecode, "%v: %v", msg, err) 170 } 171 if err := req.sanityCheck(); err != nil { 172 return err 173 } 174 update, size := req.Update.decode() 175 if p.rejectUpdate(size) { 176 return errResp(ErrRequestRejected, "") 177 } 178 p.updateFlowControl(update) 179 p.updateVtParams() 180 181 if req.Hash != (common.Hash{}) { 182 if p.announceType == announceTypeNone { 183 return errResp(ErrUnexpectedResponse, "") 184 } 185 if p.announceType == announceTypeSigned { 186 if err := req.checkSignature(p.ID(), update); err != nil { 187 p.Log().Trace("Invalid announcement signature", "err", err) 188 return err 189 } 190 p.Log().Trace("Valid announcement signature") 191 } 192 p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) 193 194 // Update peer head information first and then notify the announcement 195 p.updateHead(req.Hash, req.Number, req.Td) 196 h.fetcher.announce(p, &req) 197 } 198 case msg.Code == 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 headers := resp.Headers 208 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 209 p.answeredRequest(resp.ReqID) 210 211 // Filter out the explicitly requested header by the retriever 212 if h.backend.retriever.requested(resp.ReqID) { 213 deliverMsg = &Msg{ 214 MsgType: MsgBlockHeaders, 215 ReqID: resp.ReqID, 216 Obj: resp.Headers, 217 } 218 } else { 219 // Filter out any explicitly requested headers, deliver the rest to the downloader 220 filter := len(headers) == 1 221 if filter { 222 headers = h.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) 223 } 224 if len(headers) != 0 || !filter { 225 if err := h.downloader.DeliverHeaders(p.id, headers); err != nil { 226 log.Debug("Failed to deliver headers", "err", err) 227 } 228 } 229 } 230 case msg.Code == BlockBodiesMsg: 231 p.Log().Trace("Received block bodies response") 232 var resp struct { 233 ReqID, BV uint64 234 Data []*types.Body 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 p.answeredRequest(resp.ReqID) 241 deliverMsg = &Msg{ 242 MsgType: MsgBlockBodies, 243 ReqID: resp.ReqID, 244 Obj: resp.Data, 245 } 246 case msg.Code == CodeMsg: 247 p.Log().Trace("Received code response") 248 var resp struct { 249 ReqID, BV uint64 250 Data [][]byte 251 } 252 if err := msg.Decode(&resp); err != nil { 253 return errResp(ErrDecode, "msg %v: %v", msg, err) 254 } 255 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 256 p.answeredRequest(resp.ReqID) 257 deliverMsg = &Msg{ 258 MsgType: MsgCode, 259 ReqID: resp.ReqID, 260 Obj: resp.Data, 261 } 262 case msg.Code == ReceiptsMsg: 263 p.Log().Trace("Received receipts response") 264 var resp struct { 265 ReqID, BV uint64 266 Receipts []types.Receipts 267 } 268 if err := msg.Decode(&resp); err != nil { 269 return errResp(ErrDecode, "msg %v: %v", msg, err) 270 } 271 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 272 p.answeredRequest(resp.ReqID) 273 deliverMsg = &Msg{ 274 MsgType: MsgReceipts, 275 ReqID: resp.ReqID, 276 Obj: resp.Receipts, 277 } 278 case msg.Code == ProofsV2Msg: 279 p.Log().Trace("Received les/2 proofs response") 280 var resp struct { 281 ReqID, BV uint64 282 Data light.NodeList 283 } 284 if err := msg.Decode(&resp); err != nil { 285 return errResp(ErrDecode, "msg %v: %v", msg, err) 286 } 287 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 288 p.answeredRequest(resp.ReqID) 289 deliverMsg = &Msg{ 290 MsgType: MsgProofsV2, 291 ReqID: resp.ReqID, 292 Obj: resp.Data, 293 } 294 case msg.Code == HelperTrieProofsMsg: 295 p.Log().Trace("Received helper trie proof response") 296 var resp struct { 297 ReqID, BV uint64 298 Data HelperTrieResps 299 } 300 if err := msg.Decode(&resp); err != nil { 301 return errResp(ErrDecode, "msg %v: %v", msg, err) 302 } 303 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 304 p.answeredRequest(resp.ReqID) 305 deliverMsg = &Msg{ 306 MsgType: MsgHelperTrieProofs, 307 ReqID: resp.ReqID, 308 Obj: resp.Data, 309 } 310 case msg.Code == TxStatusMsg: 311 p.Log().Trace("Received tx status response") 312 var resp struct { 313 ReqID, BV uint64 314 Status []light.TxStatus 315 } 316 if err := msg.Decode(&resp); err != nil { 317 return errResp(ErrDecode, "msg %v: %v", msg, err) 318 } 319 p.fcServer.ReceivedReply(resp.ReqID, resp.BV) 320 p.answeredRequest(resp.ReqID) 321 deliverMsg = &Msg{ 322 MsgType: MsgTxStatus, 323 ReqID: resp.ReqID, 324 Obj: resp.Status, 325 } 326 case msg.Code == StopMsg && p.version >= lpv3: 327 p.freeze() 328 h.backend.retriever.frozen(p) 329 p.Log().Debug("Service stopped") 330 case msg.Code == ResumeMsg && p.version >= lpv3: 331 var bv uint64 332 if err := msg.Decode(&bv); err != nil { 333 return errResp(ErrDecode, "msg %v: %v", msg, err) 334 } 335 p.fcServer.ResumeFreeze(bv) 336 p.unfreeze() 337 p.Log().Debug("Service resumed") 338 default: 339 p.Log().Trace("Received invalid message", "code", msg.Code) 340 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 341 } 342 // Deliver the received response to retriever. 343 if deliverMsg != nil { 344 if err := h.backend.retriever.deliver(p, deliverMsg); err != nil { 345 if val := p.errCount.Add(1, mclock.Now()); val > maxResponseErrors { 346 return err 347 } 348 } 349 } 350 return nil 351 } 352 353 func (h *clientHandler) removePeer(id string) { 354 h.backend.peers.unregister(id) 355 } 356 357 type peerConnection struct { 358 handler *clientHandler 359 peer *serverPeer 360 } 361 362 func (pc *peerConnection) Head() (common.Hash, *big.Int) { 363 return pc.peer.HeadAndTd() 364 } 365 366 func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 367 rq := &distReq{ 368 getCost: func(dp distPeer) uint64 { 369 peer := dp.(*serverPeer) 370 return peer.getRequestCost(GetBlockHeadersMsg, amount) 371 }, 372 canSend: func(dp distPeer) bool { 373 return dp.(*serverPeer) == pc.peer 374 }, 375 request: func(dp distPeer) func() { 376 reqID := genReqID() 377 peer := dp.(*serverPeer) 378 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 379 peer.fcServer.QueuedRequest(reqID, cost) 380 return func() { peer.requestHeadersByHash(reqID, origin, amount, skip, reverse) } 381 }, 382 } 383 _, ok := <-pc.handler.backend.reqDist.queue(rq) 384 if !ok { 385 return light.ErrNoPeers 386 } 387 return nil 388 } 389 390 func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 391 rq := &distReq{ 392 getCost: func(dp distPeer) uint64 { 393 peer := dp.(*serverPeer) 394 return peer.getRequestCost(GetBlockHeadersMsg, amount) 395 }, 396 canSend: func(dp distPeer) bool { 397 return dp.(*serverPeer) == pc.peer 398 }, 399 request: func(dp distPeer) func() { 400 reqID := genReqID() 401 peer := dp.(*serverPeer) 402 cost := peer.getRequestCost(GetBlockHeadersMsg, amount) 403 peer.fcServer.QueuedRequest(reqID, cost) 404 return func() { peer.requestHeadersByNumber(reqID, origin, amount, skip, reverse) } 405 }, 406 } 407 _, ok := <-pc.handler.backend.reqDist.queue(rq) 408 if !ok { 409 return light.ErrNoPeers 410 } 411 return nil 412 } 413 414 // RetrieveSingleHeaderByNumber requests a single header by the specified block 415 // number. This function will wait the response until it's timeout or delivered. 416 func (pc *peerConnection) RetrieveSingleHeaderByNumber(context context.Context, number uint64) (*types.Header, error) { 417 reqID := genReqID() 418 rq := &distReq{ 419 getCost: func(dp distPeer) uint64 { 420 peer := dp.(*serverPeer) 421 return peer.getRequestCost(GetBlockHeadersMsg, 1) 422 }, 423 canSend: func(dp distPeer) bool { 424 return dp.(*serverPeer) == pc.peer 425 }, 426 request: func(dp distPeer) func() { 427 peer := dp.(*serverPeer) 428 cost := peer.getRequestCost(GetBlockHeadersMsg, 1) 429 peer.fcServer.QueuedRequest(reqID, cost) 430 return func() { peer.requestHeadersByNumber(reqID, number, 1, 0, false) } 431 }, 432 } 433 var header *types.Header 434 if err := pc.handler.backend.retriever.retrieve(context, reqID, rq, func(peer distPeer, msg *Msg) error { 435 if msg.MsgType != MsgBlockHeaders { 436 return errInvalidMessageType 437 } 438 headers := msg.Obj.([]*types.Header) 439 if len(headers) != 1 { 440 return errInvalidEntryCount 441 } 442 header = headers[0] 443 return nil 444 }, nil); err != nil { 445 return nil, err 446 } 447 return header, nil 448 } 449 450 // downloaderPeerNotify implements peerSetNotify 451 type downloaderPeerNotify clientHandler 452 453 func (d *downloaderPeerNotify) registerPeer(p *serverPeer) { 454 h := (*clientHandler)(d) 455 pc := &peerConnection{ 456 handler: h, 457 peer: p, 458 } 459 h.downloader.RegisterLightPeer(p.id, ethVersion, pc) 460 } 461 462 func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) { 463 h := (*clientHandler)(d) 464 h.downloader.UnregisterPeer(p.id) 465 }