github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/beacon/light/api/api_server.go (about) 1 // Copyright 2023 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 api 18 19 import ( 20 "reflect" 21 22 "github.com/ethereum/go-ethereum/beacon/light/request" 23 "github.com/ethereum/go-ethereum/beacon/light/sync" 24 "github.com/ethereum/go-ethereum/beacon/types" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/log" 27 ) 28 29 // ApiServer is a wrapper around BeaconLightApi that implements request.requestServer. 30 type ApiServer struct { 31 api *BeaconLightApi 32 eventCallback func(event request.Event) 33 unsubscribe func() 34 } 35 36 // NewApiServer creates a new ApiServer. 37 func NewApiServer(api *BeaconLightApi) *ApiServer { 38 return &ApiServer{api: api} 39 } 40 41 // Subscribe implements request.requestServer. 42 func (s *ApiServer) Subscribe(eventCallback func(event request.Event)) { 43 s.eventCallback = eventCallback 44 listener := HeadEventListener{ 45 OnNewHead: func(slot uint64, blockRoot common.Hash) { 46 log.Debug("New head received", "slot", slot, "blockRoot", blockRoot) 47 eventCallback(request.Event{Type: sync.EvNewHead, Data: types.HeadInfo{Slot: slot, BlockRoot: blockRoot}}) 48 }, 49 OnOptimistic: func(update types.OptimisticUpdate) { 50 log.Debug("New optimistic update received", "slot", update.Attested.Slot, "blockRoot", update.Attested.Hash(), "signerCount", update.Signature.SignerCount()) 51 eventCallback(request.Event{Type: sync.EvNewOptimisticUpdate, Data: update}) 52 }, 53 OnFinality: func(update types.FinalityUpdate) { 54 log.Debug("New finality update received", "slot", update.Attested.Slot, "blockRoot", update.Attested.Hash(), "signerCount", update.Signature.SignerCount()) 55 eventCallback(request.Event{Type: sync.EvNewFinalityUpdate, Data: update}) 56 }, 57 OnError: func(err error) { 58 log.Warn("Head event stream error", "err", err) 59 }, 60 } 61 s.unsubscribe = s.api.StartHeadListener(listener) 62 } 63 64 // SendRequest implements request.requestServer. 65 func (s *ApiServer) SendRequest(id request.ID, req request.Request) { 66 go func() { 67 var resp request.Response 68 var err error 69 switch data := req.(type) { 70 case sync.ReqUpdates: 71 log.Debug("Beacon API: requesting light client update", "reqid", id, "period", data.FirstPeriod, "count", data.Count) 72 var r sync.RespUpdates 73 r.Updates, r.Committees, err = s.api.GetBestUpdatesAndCommittees(data.FirstPeriod, data.Count) 74 resp = r 75 case sync.ReqHeader: 76 var r sync.RespHeader 77 log.Debug("Beacon API: requesting header", "reqid", id, "hash", common.Hash(data)) 78 r.Header, r.Canonical, r.Finalized, err = s.api.GetHeader(common.Hash(data)) 79 resp = r 80 case sync.ReqCheckpointData: 81 log.Debug("Beacon API: requesting checkpoint data", "reqid", id, "hash", common.Hash(data)) 82 resp, err = s.api.GetCheckpointData(common.Hash(data)) 83 case sync.ReqBeaconBlock: 84 log.Debug("Beacon API: requesting block", "reqid", id, "hash", common.Hash(data)) 85 resp, err = s.api.GetBeaconBlock(common.Hash(data)) 86 case sync.ReqFinality: 87 log.Debug("Beacon API: requesting finality update") 88 resp, err = s.api.GetFinalityUpdate() 89 default: 90 } 91 92 if err != nil { 93 log.Warn("Beacon API request failed", "type", reflect.TypeOf(req), "reqid", id, "err", err) 94 s.eventCallback(request.Event{Type: request.EvFail, Data: request.RequestResponse{ID: id, Request: req}}) 95 } else { 96 log.Debug("Beacon API request answered", "type", reflect.TypeOf(req), "reqid", id) 97 s.eventCallback(request.Event{Type: request.EvResponse, Data: request.RequestResponse{ID: id, Request: req, Response: resp}}) 98 } 99 }() 100 } 101 102 // Unsubscribe implements request.requestServer. 103 // Note: Unsubscribe should not be called concurrently with Subscribe. 104 func (s *ApiServer) Unsubscribe() { 105 if s.unsubscribe != nil { 106 s.unsubscribe() 107 s.unsubscribe = nil 108 } 109 } 110 111 // Name implements request.Server 112 func (s *ApiServer) Name() string { 113 return s.api.url 114 }