Merge pull request #80 from GrapeBaBa/lc_api

feat:add light client types
This commit is contained in:
彭振 2024-04-09 11:51:11 +08:00 committed by GitHub
commit d9d612d94a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 179 additions and 49 deletions

View file

@ -1,57 +1,39 @@
package api
import (
"errors"
"time"
"github.com/ethereum/go-ethereum/beacon/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/portalnetwork/beacon"
"github.com/protolambda/zrnt/eth2/beacon/capella"
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/ztyp/tree"
)
type PortalLightApi struct {
bn *beacon.BeaconNetwork
}
func NewPortalLightApi() *PortalLightApi {
return &PortalLightApi{}
}
func (api *PortalLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) {
//contentKey := &beacon.LightClientUpdateKey{
// StartPeriod: firstPeriod,
// Count: count,
//}
//resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count)
//if err != nil {
// return nil, nil, err
//}
//
//var data []CommitteeUpdate
//if err := json.Unmarshal(resp, &data); err != nil {
// return nil, nil, err
//}
//if len(data) != int(count) {
// return nil, nil, errors.New("invalid number of committee updates")
//}
//updates := make([]*types.LightClientUpdate, int(count))
//committees := make([]*types.SerializedSyncCommittee, int(count))
//for i, d := range data {
// if d.Update.AttestedHeader.Header.SyncPeriod() != firstPeriod+uint64(i) {
// return nil, nil, errors.New("wrong committee update header period")
// }
// if err := d.Update.Validate(); err != nil {
// return nil, nil, err
// }
// if d.NextSyncCommittee.Root() != d.Update.NextSyncCommitteeRoot {
// return nil, nil, errors.New("wrong sync committee root")
// }
// updates[i], committees[i] = new(types.LightClientUpdate), new(types.SerializedSyncCommittee)
// *updates[i], *committees[i] = d.Update, d.NextSyncCommittee
//}
//return updates, committees, nil
return nil, nil, errors.New("not implemented")
func (api *PortalLightApi) GetUpdates(firstPeriod, count uint64) (beacon.LightClientUpdateRange, error) {
return api.bn.GetUpdates(firstPeriod, count)
}
func (api *PortalLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) {
return nil, errors.New("not implemented")
func (api *PortalLightApi) GetCheckpointData(checkpointHash tree.Root) (*capella.LightClientBootstrap, error) {
return api.bn.GetCheckpointData(checkpointHash)
}
func (api *PortalLightApi) GetFinalityData() (*capella.LightClientFinalityUpdate, error) {
expectedCurrentSlot := api.bn.Spec.TimeToSlot(zrntcommon.Timestamp(time.Now().Unix()), zrntcommon.Timestamp(beacon.BeaconGenesisTime))
recentEpochStart := expectedCurrentSlot - (expectedCurrentSlot % api.bn.Spec.SLOTS_PER_EPOCH) + 1
return api.bn.GetFinalityUpdate(uint64(recentEpochStart))
}
func (api *PortalLightApi) GetOptimisticData() (*capella.LightClientOptimisticUpdate, error) {
expectedCurrentSlot := api.bn.Spec.TimeToSlot(zrntcommon.Timestamp(time.Now().Unix()), zrntcommon.Timestamp(beacon.BeaconGenesisTime))
return api.bn.GetOptimisticUpdate(uint64(expectedCurrentSlot))
}

View file

@ -19,14 +19,15 @@ const (
LightClientFinalityUpdate storage.ContentType = 0x12
LightClientOptimisticUpdate storage.ContentType = 0x13
HistoricalSummaries storage.ContentType = 0x14
BeaconGenesisTime uint64 = 1606824023
)
type BeaconNetwork struct {
portalProtocol *discover.PortalProtocol
spec *common.Spec
PortalProtocol *discover.PortalProtocol
Spec *common.Spec
}
func (bn *BeaconNetwork) GetBestUpdatesAndCommittees(firstPeriod, count uint64) (LightClientUpdateRange, error) {
func (bn *BeaconNetwork) GetUpdates(firstPeriod, count uint64) (LightClientUpdateRange, error) {
lightClientUpdateKey := &LightClientUpdateKey{
StartPeriod: firstPeriod,
Count: count,
@ -38,7 +39,7 @@ func (bn *BeaconNetwork) GetBestUpdatesAndCommittees(firstPeriod, count uint64)
}
var lightClientUpdateRange LightClientUpdateRange = make([]ForkedLightClientUpdate, 0)
err = lightClientUpdateRange.Deserialize(bn.spec, codec.NewDecodingReader(bytes.NewReader(lightClientUpdateRangeContent), uint64(len(lightClientUpdateRangeContent))))
err = lightClientUpdateRange.Deserialize(bn.Spec, codec.NewDecodingReader(bytes.NewReader(lightClientUpdateRangeContent), uint64(len(lightClientUpdateRangeContent))))
if err != nil {
return nil, err
}
@ -57,7 +58,7 @@ func (bn *BeaconNetwork) GetCheckpointData(checkpointHash tree.Root) (*capella.L
}
var forkedLightClientBootstrap ForkedLightClientBootstrap
err = forkedLightClientBootstrap.Deserialize(bn.spec, codec.NewDecodingReader(bytes.NewReader(bootstrapValue), uint64(len(bootstrapValue))))
err = forkedLightClientBootstrap.Deserialize(bn.Spec, codec.NewDecodingReader(bytes.NewReader(bootstrapValue), uint64(len(bootstrapValue))))
if err != nil {
return nil, err
}
@ -69,6 +70,52 @@ func (bn *BeaconNetwork) GetCheckpointData(checkpointHash tree.Root) (*capella.L
return forkedLightClientBootstrap.Bootstrap.(*capella.LightClientBootstrap), nil
}
func (bn *BeaconNetwork) GetFinalityUpdate(finalizedSlot uint64) (*capella.LightClientFinalityUpdate, error) {
finalityUpdateKey := &LightClientFinalityUpdateKey{
FinalizedSlot: finalizedSlot,
}
finalityUpdateValue, err := bn.getContent(LightClientFinalityUpdate, finalityUpdateKey)
if err != nil {
return nil, err
}
var forkedLightClientFinalityUpdate ForkedLightClientFinalityUpdate
err = forkedLightClientFinalityUpdate.Deserialize(bn.Spec, codec.NewDecodingReader(bytes.NewReader(finalityUpdateValue), uint64(len(finalityUpdateValue))))
if err != nil {
return nil, err
}
if forkedLightClientFinalityUpdate.ForkDigest != Capella {
return nil, errors.New("unknown fork digest")
}
return forkedLightClientFinalityUpdate.LightClientFinalityUpdate.(*capella.LightClientFinalityUpdate), nil
}
func (bn *BeaconNetwork) GetOptimisticUpdate(optimisticSlot uint64) (*capella.LightClientOptimisticUpdate, error) {
optimisticUpdateKey := &LightClientOptimisticUpdateKey{
OptimisticSlot: optimisticSlot,
}
optimisticUpdateValue, err := bn.getContent(LightClientOptimisticUpdate, optimisticUpdateKey)
if err != nil {
return nil, err
}
var forkedLightClientOptimisticUpdate ForkedLightClientOptimisticUpdate
err = forkedLightClientOptimisticUpdate.Deserialize(bn.Spec, codec.NewDecodingReader(bytes.NewReader(optimisticUpdateValue), uint64(len(optimisticUpdateValue))))
if err != nil {
return nil, err
}
if forkedLightClientOptimisticUpdate.ForkDigest != Capella {
return nil, errors.New("unknown fork digest")
}
return forkedLightClientOptimisticUpdate.LightClientOptimisticUpdate.(*capella.LightClientOptimisticUpdate), nil
}
func (bn *BeaconNetwork) getContent(contentType storage.ContentType, beaconContentKey ssz.Marshaler) ([]byte, error) {
contentKeyBytes, err := beaconContentKey.MarshalSSZ()
if err != nil {
@ -76,9 +123,9 @@ func (bn *BeaconNetwork) getContent(contentType storage.ContentType, beaconConte
}
contentKey := storage.NewContentKey(contentType, contentKeyBytes).Encode()
contentId := bn.portalProtocol.ToContentId(contentKey)
contentId := bn.PortalProtocol.ToContentId(contentKey)
res, err := bn.portalProtocol.Get(contentKey, contentId)
res, err := bn.PortalProtocol.Get(contentKey, contentId)
// other error
if err != nil && !errors.Is(err, storage.ErrContentNotFound) {
return nil, err
@ -88,7 +135,7 @@ func (bn *BeaconNetwork) getContent(contentType storage.ContentType, beaconConte
return res, nil
}
content, _, err := bn.portalProtocol.ContentLookup(contentKey, contentId)
content, _, err := bn.PortalProtocol.ContentLookup(contentKey, contentId)
if err != nil {
return nil, err
}

View file

@ -0,0 +1,53 @@
package beacon
import (
"github.com/protolambda/zrnt/eth2/beacon/capella"
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/ztyp/view"
)
type ConsensusAPI interface {
GetUpdates(firstPeriod, count uint64) (LightClientUpdateRange, error)
GetCheckpointData(checkpointHash common.Root) (*capella.LightClientBootstrap, error)
GetFinalityData() (*capella.LightClientFinalityUpdate, error)
GetOptimisticData() (*capella.LightClientOptimisticUpdate, error)
ChainID() uint64
Name() string
}
type LightClientStore struct {
FinalizedHeader common.BeaconBlockHeader
CurrentSyncCommittee common.SyncCommittee
NextSyncCommittee common.SyncCommittee
OptimisticHeader common.BeaconBlockHeader
PreviousMaxActiveParticipants view.Uint64View
CurrentMaxActiveParticipants view.Uint64View
}
type ConsensusLightClient struct {
Store LightClientStore
API ConsensusAPI
InitialCheckpoint common.Root
LastCheckpoint common.Root
Config Config
}
type Config struct {
ConsensusAPI string
Port uint64
DefaultCheckpoint common.Root
Checkpoint common.Root
DataDir string
ChainConfig ChainConfig
Spec *common.Spec
MaxCheckpointAge uint64
Fallback string
LoadExternalFallback bool
StrictCheckpointAge bool
}
type ChainConfig struct {
ChainID uint64
GenesisTime uint64
GenesisRoot common.Root
}

View file

@ -0,0 +1,48 @@
package beacon
import (
"time"
"github.com/protolambda/zrnt/eth2/beacon/capella"
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/ztyp/tree"
)
var _ ConsensusAPI = &PortalLightApi{}
type PortalLightApi struct {
bn *BeaconNetwork
}
func NewPortalLightApi() *PortalLightApi {
return &PortalLightApi{}
}
func (api *PortalLightApi) GetUpdates(firstPeriod, count uint64) (LightClientUpdateRange, error) {
return api.bn.GetUpdates(firstPeriod, count)
}
func (api *PortalLightApi) GetCheckpointData(checkpointHash tree.Root) (*capella.LightClientBootstrap, error) {
return api.bn.GetCheckpointData(checkpointHash)
}
func (api *PortalLightApi) GetFinalityData() (*capella.LightClientFinalityUpdate, error) {
expectedCurrentSlot := api.bn.Spec.TimeToSlot(zrntcommon.Timestamp(time.Now().Unix()), zrntcommon.Timestamp(BeaconGenesisTime))
recentEpochStart := expectedCurrentSlot - (expectedCurrentSlot % api.bn.Spec.SLOTS_PER_EPOCH) + 1
return api.bn.GetFinalityUpdate(uint64(recentEpochStart))
}
func (api *PortalLightApi) GetOptimisticData() (*capella.LightClientOptimisticUpdate, error) {
expectedCurrentSlot := api.bn.Spec.TimeToSlot(zrntcommon.Timestamp(time.Now().Unix()), zrntcommon.Timestamp(BeaconGenesisTime))
return api.bn.GetOptimisticUpdate(uint64(expectedCurrentSlot))
}
func (api *PortalLightApi) ChainID() uint64 {
return 1
}
func (api *PortalLightApi) Name() string {
return "portal"
}