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  }