mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
Read lc updates from LCStore in RPC (#15172)
* add lcstore to rpc config and lc server * read updates from store * remove unused func * optimistic tests * finality tests * changelog entry * Update changelog/bastin_read-updates-from-store-in-rpc.md Co-authored-by: Radosław Kapka <rkapka@wp.pl> * pass lcstore to rpc service --------- Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
@@ -1011,6 +1011,7 @@ func (b *BeaconNode) registerRPCService(router *http.ServeMux) error {
|
||||
BlobStorage: b.BlobStorage,
|
||||
TrackedValidatorsCache: b.trackedValidatorsCache,
|
||||
PayloadIDCache: b.payloadIDCache,
|
||||
LCStore: b.lcStore,
|
||||
})
|
||||
|
||||
return b.services.RegisterService(rpcService)
|
||||
|
||||
@@ -20,6 +20,7 @@ go_library(
|
||||
"//beacon-chain/core/feed/block:go_default_library",
|
||||
"//beacon-chain/core/feed/operation:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/core/light-client:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/db/filesystem:go_default_library",
|
||||
"//beacon-chain/execution:go_default_library",
|
||||
|
||||
@@ -946,6 +946,7 @@ func (s *Service) lightClientEndpoints(blocker lookup.Blocker, stater lookup.Sta
|
||||
HeadFetcher: s.cfg.HeadFetcher,
|
||||
ChainInfoFetcher: s.cfg.ChainInfoFetcher,
|
||||
BeaconDB: s.cfg.BeaconDB,
|
||||
LCStore: s.cfg.LCStore,
|
||||
}
|
||||
|
||||
const namespace = "lightclient"
|
||||
|
||||
@@ -19,7 +19,6 @@ go_library(
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//monitoring/tracing/trace:go_default_library",
|
||||
"//network/forks:go_default_library",
|
||||
@@ -27,7 +26,6 @@ go_library(
|
||||
"//runtime/version:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -45,12 +43,10 @@ go_test(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/light-client:go_default_library",
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//beacon-chain/rpc/testutil:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/light-client:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
package lightclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api"
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
lightclient "github.com/OffchainLabs/prysm/v6/beacon-chain/core/light-client"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared"
|
||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
||||
@@ -21,7 +17,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
)
|
||||
|
||||
@@ -197,70 +192,32 @@ func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.R
|
||||
return
|
||||
}
|
||||
|
||||
ctx, span := trace.StartSpan(req.Context(), "beacon.GetLightClientFinalityUpdate")
|
||||
_, span := trace.StartSpan(req.Context(), "beacon.GetLightClientFinalityUpdate")
|
||||
defer span.End()
|
||||
|
||||
// Finality update needs super majority of sync committee signatures
|
||||
minSyncCommitteeParticipants := float64(params.BeaconConfig().MinSyncCommitteeParticipants)
|
||||
minSignatures := uint64(math.Ceil(minSyncCommitteeParticipants * 2 / 3))
|
||||
|
||||
block, err := s.suitableBlock(ctx, minSignatures)
|
||||
if !shared.WriteBlockFetchError(w, block, err) {
|
||||
return
|
||||
}
|
||||
|
||||
st, err := s.Stater.StateBySlot(ctx, block.Block().Slot())
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
attestedRoot := block.Block().ParentRoot()
|
||||
attestedBlock, err := s.Blocker.Block(ctx, attestedRoot[:])
|
||||
if !shared.WriteBlockFetchError(w, block, errors.Wrap(err, "could not get attested block")) {
|
||||
return
|
||||
}
|
||||
attestedSlot := attestedBlock.Block().Slot()
|
||||
attestedState, err := s.Stater.StateBySlot(ctx, attestedSlot)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get attested state: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var finalizedBlock interfaces.ReadOnlySignedBeaconBlock
|
||||
finalizedCheckpoint := attestedState.FinalizedCheckpoint()
|
||||
if finalizedCheckpoint == nil {
|
||||
httputil.HandleError(w, "Attested state does not have a finalized checkpoint", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
finalizedRoot := bytesutil.ToBytes32(finalizedCheckpoint.Root)
|
||||
finalizedBlock, err = s.Blocker.Block(ctx, finalizedRoot[:])
|
||||
if !shared.WriteBlockFetchError(w, block, errors.Wrap(err, "could not get finalized block")) {
|
||||
return
|
||||
}
|
||||
|
||||
update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), st, block, attestedState, attestedBlock, finalizedBlock)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError)
|
||||
update := s.LCStore.LastFinalityUpdate()
|
||||
if update == nil {
|
||||
httputil.HandleError(w, "No light client finality update available", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(api.VersionHeader, version.String(update.Version()))
|
||||
if httputil.RespondWithSsz(req) {
|
||||
ssz, err := update.MarshalSSZ()
|
||||
data, err := update.MarshalSSZ()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not marshal finality update to SSZ: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httputil.WriteSsz(w, ssz)
|
||||
httputil.WriteSsz(w, data)
|
||||
} else {
|
||||
updateStruct, err := structs.LightClientFinalityUpdateFromConsensus(update)
|
||||
data, err := structs.LightClientFinalityUpdateFromConsensus(update)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not convert light client finality update to API struct: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response := &structs.LightClientFinalityUpdateResponse{
|
||||
Version: version.String(attestedState.Version()),
|
||||
Data: updateStruct,
|
||||
Version: version.String(update.Version()),
|
||||
Data: data,
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
@@ -273,111 +230,33 @@ func (s *Server) GetLightClientOptimisticUpdate(w http.ResponseWriter, req *http
|
||||
return
|
||||
}
|
||||
|
||||
ctx, span := trace.StartSpan(req.Context(), "beacon.GetLightClientOptimisticUpdate")
|
||||
_, span := trace.StartSpan(req.Context(), "beacon.GetLightClientOptimisticUpdate")
|
||||
defer span.End()
|
||||
|
||||
block, err := s.suitableBlock(ctx, params.BeaconConfig().MinSyncCommitteeParticipants)
|
||||
if !shared.WriteBlockFetchError(w, block, err) {
|
||||
return
|
||||
}
|
||||
st, err := s.Stater.StateBySlot(ctx, block.Block().Slot())
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "could not get state: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
attestedRoot := block.Block().ParentRoot()
|
||||
attestedBlock, err := s.Blocker.Block(ctx, attestedRoot[:])
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get attested block: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if attestedBlock == nil {
|
||||
httputil.HandleError(w, "Attested block is nil", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
attestedSlot := attestedBlock.Block().Slot()
|
||||
attestedState, err := s.Stater.StateBySlot(ctx, attestedSlot)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get attested state: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), st, block, attestedState, attestedBlock)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get light client optimistic update: "+err.Error(), http.StatusInternalServerError)
|
||||
update := s.LCStore.LastOptimisticUpdate()
|
||||
if update == nil {
|
||||
httputil.HandleError(w, "No light client optimistic update available", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(api.VersionHeader, version.String(update.Version()))
|
||||
if httputil.RespondWithSsz(req) {
|
||||
ssz, err := update.MarshalSSZ()
|
||||
data, err := update.MarshalSSZ()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not marshal optimistic update to SSZ: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httputil.WriteSsz(w, ssz)
|
||||
httputil.WriteSsz(w, data)
|
||||
} else {
|
||||
updateStruct, err := structs.LightClientOptimisticUpdateFromConsensus(update)
|
||||
data, err := structs.LightClientOptimisticUpdateFromConsensus(update)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not convert light client optimistic update to API struct: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response := &structs.LightClientOptimisticUpdateResponse{
|
||||
Version: version.String(attestedState.Version()),
|
||||
Data: updateStruct,
|
||||
Version: version.String(update.Version()),
|
||||
Data: data,
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
}
|
||||
|
||||
// suitableBlock returns the latest block that satisfies all criteria required for creating a new update
|
||||
func (s *Server) suitableBlock(ctx context.Context, minSignaturesRequired uint64) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||
st, err := s.HeadFetcher.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get head state")
|
||||
}
|
||||
|
||||
latestBlockHeader := st.LatestBlockHeader()
|
||||
stateRoot, err := st.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get state root")
|
||||
}
|
||||
latestBlockHeader.StateRoot = stateRoot[:]
|
||||
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get latest block header root")
|
||||
}
|
||||
|
||||
block, err := s.Blocker.Block(ctx, latestBlockHeaderRoot[:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get latest block")
|
||||
}
|
||||
if block == nil {
|
||||
return nil, errors.New("latest block is nil")
|
||||
}
|
||||
|
||||
// Loop through the blocks until we find a block that satisfies minSignaturesRequired requirement
|
||||
var numOfSyncCommitteeSignatures uint64
|
||||
if syncAggregate, err := block.Block().Body().SyncAggregate(); err == nil {
|
||||
numOfSyncCommitteeSignatures = syncAggregate.SyncCommitteeBits.Count()
|
||||
}
|
||||
|
||||
for numOfSyncCommitteeSignatures < minSignaturesRequired {
|
||||
// Get the parent block
|
||||
parentRoot := block.Block().ParentRoot()
|
||||
block, err = s.Blocker.Block(ctx, parentRoot[:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get parent block")
|
||||
}
|
||||
if block == nil {
|
||||
return nil, errors.New("parent block is nil")
|
||||
}
|
||||
|
||||
// Get the number of sync committee signatures
|
||||
numOfSyncCommitteeSignatures = 0
|
||||
if syncAggregate, err := block.Block().Body().SyncAggregate(); err == nil {
|
||||
numOfSyncCommitteeSignatures = syncAggregate.SyncCommitteeBits.Count()
|
||||
}
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ package lightclient
|
||||
|
||||
import (
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain"
|
||||
lightClient "github.com/OffchainLabs/prysm/v6/beacon-chain/core/light-client"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/lookup"
|
||||
)
|
||||
@@ -12,4 +13,5 @@ type Server struct {
|
||||
HeadFetcher blockchain.HeadFetcher
|
||||
ChainInfoFetcher blockchain.ChainInfoFetcher
|
||||
BeaconDB db.HeadAccessDatabase
|
||||
LCStore *lightClient.Store
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
blockfeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/block"
|
||||
opfeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/operation"
|
||||
statefeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/state"
|
||||
lightClient "github.com/OffchainLabs/prysm/v6/beacon-chain/core/light-client"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution"
|
||||
@@ -121,6 +122,7 @@ type Config struct {
|
||||
BlobStorage *filesystem.BlobStorage
|
||||
TrackedValidatorsCache *cache.TrackedValidatorsCache
|
||||
PayloadIDCache *cache.PayloadIDCache
|
||||
LCStore *lightClient.Store
|
||||
}
|
||||
|
||||
// NewService instantiates a new RPC service instance that will
|
||||
|
||||
3
changelog/bastin_read-updates-from-store-in-rpc.md
Normal file
3
changelog/bastin_read-updates-from-store-in-rpc.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Read light client optimistic and finality updates from LCStore instead of computing them in the beacon API handlers.
|
||||
Reference in New Issue
Block a user