save light client updates (diff) (#14683)

* update diff

* deps

* add tests for `SaveLightClientUpdate`

* cleanup imports

* lint

* changelog

* fix incorrect arithmetic

* check for lightclient feature flag

* fix tests

* fix `saveLightClientBootstrap` and `saveLightClientUpdate`

* replace and with or

* move feature check to `postBlockProcess`

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
Rupam Dey
2024-12-05 02:52:43 +05:30
committed by GitHub
parent b23c562b67
commit 30a136f1fb
40 changed files with 3839 additions and 3448 deletions

View File

@@ -31,6 +31,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- P2P: Add logs when a peer is (dis)connected. Add the reason of the disconnection when we initiate it. - P2P: Add logs when a peer is (dis)connected. Add the reason of the disconnection when we initiate it.
- Added a Prometheus error counter metric for HTTP requests to track beacon node requests. - Added a Prometheus error counter metric for HTTP requests to track beacon node requests.
- Added a Prometheus error counter metric for SSE requests. - Added a Prometheus error counter metric for SSE requests.
- Save light client updates and bootstraps in DB.
### Changed ### Changed

View File

@@ -36,9 +36,8 @@ go_library(
"//math:go_default_library", "//math:go_default_library",
"//proto/engine/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library", "//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library", "@com_github_pkg_errors//:go_default_library",

View File

@@ -1546,3 +1546,10 @@ func EventChainReorgFromV1(event *ethv1.EventChainReorg) *ChainReorgEvent {
ExecutionOptimistic: event.ExecutionOptimistic, ExecutionOptimistic: event.ExecutionOptimistic,
} }
} }
func SyncAggregateFromConsensus(sa *eth.SyncAggregate) *SyncAggregate {
return &SyncAggregate{
SyncCommitteeBits: hexutil.Encode(sa.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(sa.SyncCommitteeSignature),
}
}

View File

@@ -3,125 +3,227 @@ package structs
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors" "github.com/pkg/errors"
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
"github.com/prysmaticlabs/prysm/v5/proto/migration" "github.com/prysmaticlabs/prysm/v5/runtime/version"
) )
func LightClientUpdateFromConsensus(update *v2.LightClientUpdate) (*LightClientUpdate, error) { func LightClientUpdateFromConsensus(update interfaces.LightClientUpdate) (*LightClientUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) attestedHeader, err := lightClientHeaderToJSON(update.AttestedHeader())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header") return nil, errors.Wrap(err, "could not marshal attested light client header")
} }
finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader) finalizedHeader, err := lightClientHeaderToJSON(update.FinalizedHeader())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not marshal finalized light client header") return nil, errors.Wrap(err, "could not marshal finalized light client header")
} }
var scBranch [][32]byte
var finalityBranch [][32]byte
if update.Version() >= version.Electra {
scb, err := update.NextSyncCommitteeBranchElectra()
if err != nil {
return nil, err
}
scBranch = scb[:]
fb, err := update.FinalityBranchElectra()
if err != nil {
return nil, err
}
finalityBranch = fb[:]
} else {
scb, err := update.NextSyncCommitteeBranch()
if err != nil {
return nil, err
}
scBranch = scb[:]
fb, err := update.FinalityBranch()
if err != nil {
return nil, err
}
finalityBranch = fb[:]
}
return &LightClientUpdate{ return &LightClientUpdate{
AttestedHeader: attestedHeader, AttestedHeader: attestedHeader,
NextSyncCommittee: SyncCommitteeFromConsensus(migration.V2SyncCommitteeToV1Alpha1(update.NextSyncCommittee)), NextSyncCommittee: SyncCommitteeFromConsensus(update.NextSyncCommittee()),
NextSyncCommitteeBranch: branchToJSON(update.NextSyncCommitteeBranch), NextSyncCommitteeBranch: branchToJSON(scBranch),
FinalizedHeader: finalizedHeader, FinalizedHeader: finalizedHeader,
FinalityBranch: branchToJSON(update.FinalityBranch), FinalityBranch: branchToJSON(finalityBranch),
SyncAggregate: syncAggregateToJSON(update.SyncAggregate), SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10), SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()),
}, nil }, nil
} }
func LightClientFinalityUpdateFromConsensus(update *v2.LightClientFinalityUpdate) (*LightClientFinalityUpdate, error) { func LightClientFinalityUpdateFromConsensus(update interfaces.LightClientFinalityUpdate) (*LightClientFinalityUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) attestedHeader, err := lightClientHeaderToJSON(update.AttestedHeader())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header") return nil, errors.Wrap(err, "could not marshal attested light client header")
} }
finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader) finalizedHeader, err := lightClientHeaderToJSON(update.FinalizedHeader())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not marshal finalized light client header") return nil, errors.Wrap(err, "could not marshal finalized light client header")
} }
var finalityBranch [][32]byte
if update.Version() >= version.Electra {
b, err := update.FinalityBranchElectra()
if err != nil {
return nil, err
}
finalityBranch = b[:]
} else {
b, err := update.FinalityBranch()
if err != nil {
return nil, err
}
finalityBranch = b[:]
}
return &LightClientFinalityUpdate{ return &LightClientFinalityUpdate{
AttestedHeader: attestedHeader, AttestedHeader: attestedHeader,
FinalizedHeader: finalizedHeader, FinalizedHeader: finalizedHeader,
FinalityBranch: branchToJSON(update.FinalityBranch), FinalityBranch: branchToJSON(finalityBranch),
SyncAggregate: syncAggregateToJSON(update.SyncAggregate), SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10), SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()),
}, nil }, nil
} }
func LightClientOptimisticUpdateFromConsensus(update *v2.LightClientOptimisticUpdate) (*LightClientOptimisticUpdate, error) { func LightClientOptimisticUpdateFromConsensus(update interfaces.LightClientOptimisticUpdate) (*LightClientOptimisticUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) attestedHeader, err := lightClientHeaderToJSON(update.AttestedHeader())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header") return nil, errors.Wrap(err, "could not marshal attested light client header")
} }
return &LightClientOptimisticUpdate{ return &LightClientOptimisticUpdate{
AttestedHeader: attestedHeader, AttestedHeader: attestedHeader,
SyncAggregate: syncAggregateToJSON(update.SyncAggregate), SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10), SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()),
}, nil }, nil
} }
func branchToJSON(branchBytes [][]byte) []string { func branchToJSON[S [][32]byte](branchBytes S) []string {
if branchBytes == nil { if branchBytes == nil {
return nil return nil
} }
branch := make([]string, len(branchBytes)) branch := make([]string, len(branchBytes))
for i, root := range branchBytes { for i, root := range branchBytes {
branch[i] = hexutil.Encode(root) branch[i] = hexutil.Encode(root[:])
} }
return branch return branch
} }
func syncAggregateToJSON(input *v1.SyncAggregate) *SyncAggregate { func lightClientHeaderToJSON(header interfaces.LightClientHeader) (json.RawMessage, error) {
return &SyncAggregate{
SyncCommitteeBits: hexutil.Encode(input.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(input.SyncCommitteeSignature),
}
}
func lightClientHeaderContainerToJSON(container *v2.LightClientHeaderContainer) (json.RawMessage, error) {
// In the case that a finalizedHeader is nil. // In the case that a finalizedHeader is nil.
if container == nil { if header == nil {
return nil, nil return nil, nil
} }
beacon, err := container.GetBeacon() var result any
if err != nil {
return nil, errors.Wrap(err, "could not get beacon block header")
}
var header any switch v := header.Version(); v {
case version.Altair:
switch t := (container.Header).(type) { result = &LightClientHeader{Beacon: BeaconBlockHeaderFromConsensus(header.Beacon())}
case *v2.LightClientHeaderContainer_HeaderAltair: case version.Capella:
header = &LightClientHeader{Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon))} exInterface, err := header.Execution()
case *v2.LightClientHeaderContainer_HeaderCapella:
execution, err := ExecutionPayloadHeaderCapellaFromConsensus(t.HeaderCapella.Execution)
if err != nil { if err != nil {
return nil, err return nil, err
} }
header = &LightClientHeaderCapella{ ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderCapella)
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)), if !ok {
Execution: execution, return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderCapella{})
ExecutionBranch: branchToJSON(t.HeaderCapella.ExecutionBranch),
} }
case *v2.LightClientHeaderContainer_HeaderDeneb: execution, err := ExecutionPayloadHeaderCapellaFromConsensus(ex)
execution, err := ExecutionPayloadHeaderDenebFromConsensus(t.HeaderDeneb.Execution)
if err != nil { if err != nil {
return nil, err return nil, err
} }
header = &LightClientHeaderDeneb{ executionBranch, err := header.ExecutionBranch()
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)), if err != nil {
return nil, err
}
result = &LightClientHeaderCapella{
Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()),
Execution: execution, Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderDeneb.ExecutionBranch), ExecutionBranch: branchToJSON(executionBranch[:]),
}
case version.Deneb:
exInterface, err := header.Execution()
if err != nil {
return nil, err
}
ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderDeneb)
if !ok {
return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderDeneb{})
}
execution, err := ExecutionPayloadHeaderDenebFromConsensus(ex)
if err != nil {
return nil, err
}
executionBranch, err := header.ExecutionBranch()
if err != nil {
return nil, err
}
result = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()),
Execution: execution,
ExecutionBranch: branchToJSON(executionBranch[:]),
}
case version.Electra:
exInterface, err := header.Execution()
if err != nil {
return nil, err
}
ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderElectra)
if !ok {
return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderElectra{})
}
execution, err := ExecutionPayloadHeaderElectraFromConsensus(ex)
if err != nil {
return nil, err
}
executionBranch, err := header.ExecutionBranch()
if err != nil {
return nil, err
}
result = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()),
Execution: execution,
ExecutionBranch: branchToJSON(executionBranch[:]),
} }
default: default:
return nil, fmt.Errorf("unsupported header type %T", t) return nil, fmt.Errorf("unsupported header version %s", version.String(v))
} }
return json.Marshal(header) return json.Marshal(result)
}
func LightClientBootstrapFromConsensus(bootstrap interfaces.LightClientBootstrap) (*LightClientBootstrap, error) {
header, err := lightClientHeaderToJSON(bootstrap.Header())
if err != nil {
return nil, errors.Wrap(err, "could not marshal light client header")
}
var scBranch [][32]byte
if bootstrap.Version() >= version.Electra {
b, err := bootstrap.CurrentSyncCommitteeBranchElectra()
if err != nil {
return nil, err
}
scBranch = b[:]
} else {
b, err := bootstrap.CurrentSyncCommitteeBranch()
if err != nil {
return nil, err
}
scBranch = b[:]
}
return &LightClientBootstrap{
Header: header,
CurrentSyncCommittee: SyncCommitteeFromConsensus(bootstrap.CurrentSyncCommittee()),
CurrentSyncCommitteeBranch: branchToJSON(scBranch),
}, nil
} }

View File

@@ -84,7 +84,6 @@ go_library(
"//monitoring/tracing/trace:go_default_library", "//monitoring/tracing/trace:go_default_library",
"//proto/engine/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library", "//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library", "//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library", "//runtime/version:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
@@ -39,7 +38,7 @@ func prepareForkchoiceState(
payloadHash [32]byte, payloadHash [32]byte,
justified *ethpb.Checkpoint, justified *ethpb.Checkpoint,
finalized *ethpb.Checkpoint, finalized *ethpb.Checkpoint,
) (state.BeaconState, consensus_blocks.ROBlock, error) { ) (state.BeaconState, blocks.ROBlock, error) {
blockHeader := &ethpb.BeaconBlockHeader{ blockHeader := &ethpb.BeaconBlockHeader{
ParentRoot: parentRoot[:], ParentRoot: parentRoot[:],
} }
@@ -61,7 +60,7 @@ func prepareForkchoiceState(
base.BlockRoots[0] = append(base.BlockRoots[0], blockRoot[:]...) base.BlockRoots[0] = append(base.BlockRoots[0], blockRoot[:]...)
st, err := state_native.InitializeFromProtoBellatrix(base) st, err := state_native.InitializeFromProtoBellatrix(base)
if err != nil { if err != nil {
return nil, consensus_blocks.ROBlock{}, err return nil, blocks.ROBlock{}, err
} }
blk := &ethpb.SignedBeaconBlockBellatrix{ blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{ Block: &ethpb.BeaconBlockBellatrix{
@@ -76,9 +75,9 @@ func prepareForkchoiceState(
} }
signed, err := blocks.NewSignedBeaconBlock(blk) signed, err := blocks.NewSignedBeaconBlock(blk)
if err != nil { if err != nil {
return nil, consensus_blocks.ROBlock{}, err return nil, blocks.ROBlock{}, err
} }
roblock, err := consensus_blocks.NewROBlockWithRoot(signed, blockRoot) roblock, err := blocks.NewROBlockWithRoot(signed, blockRoot)
return st, roblock, err return st, roblock, err
} }

View File

@@ -67,7 +67,10 @@ func (s *Service) postBlockProcess(cfg *postBlockProcessConfig) error {
if s.inRegularSync() { if s.inRegularSync() {
defer s.handleSecondFCUCall(cfg, fcuArgs) defer s.handleSecondFCUCall(cfg, fcuArgs)
} }
defer s.sendLightClientFeeds(cfg) if features.Get().EnableLightClient && slots.ToEpoch(s.CurrentSlot()) >= params.BeaconConfig().AltairForkEpoch {
defer s.processLightClientUpdates(cfg)
defer s.saveLightClientUpdate(cfg)
}
defer s.sendStateFeedOnBlock(cfg) defer s.sendStateFeedOnBlock(cfg)
defer reportProcessingTime(startTime) defer reportProcessingTime(startTime)
defer reportAttestationInclusion(cfg.roblock.Block()) defer reportAttestationInclusion(cfg.roblock.Block())

View File

@@ -15,7 +15,6 @@ import (
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree" doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/features"
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams" field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
@@ -24,7 +23,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
mathutil "github.com/prysmaticlabs/prysm/v5/math" mathutil "github.com/prysmaticlabs/prysm/v5/math"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots" "github.com/prysmaticlabs/prysm/v5/time/slots"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@@ -115,64 +113,123 @@ func (s *Service) sendStateFeedOnBlock(cfg *postBlockProcessConfig) {
}) })
} }
// sendLightClientFeeds sends the light client feeds when feature flag is enabled. func (s *Service) processLightClientUpdates(cfg *postBlockProcessConfig) {
func (s *Service) sendLightClientFeeds(cfg *postBlockProcessConfig) { if err := s.processLightClientOptimisticUpdate(cfg.ctx, cfg.roblock, cfg.postState); err != nil {
if features.Get().EnableLightClient { log.WithError(err).Error("Failed to process light client optimistic update")
if _, err := s.sendLightClientOptimisticUpdate(cfg.ctx, cfg.roblock, cfg.postState); err != nil { }
log.WithError(err).Error("Failed to send light client optimistic update") if err := s.processLightClientFinalityUpdate(cfg.ctx, cfg.roblock, cfg.postState); err != nil {
} log.WithError(err).Error("Failed to process light client finality update")
// Get the finalized checkpoint
finalized := s.ForkChoicer().FinalizedCheckpoint()
// LightClientFinalityUpdate needs super majority
s.tryPublishLightClientFinalityUpdate(cfg.ctx, cfg.roblock, finalized, cfg.postState)
} }
} }
func (s *Service) tryPublishLightClientFinalityUpdate(ctx context.Context, signed interfaces.ReadOnlySignedBeaconBlock, finalized *forkchoicetypes.Checkpoint, postState state.BeaconState) { // saveLightClientUpdate saves the light client update for this block
if finalized.Epoch <= s.lastPublishedLightClientEpoch { // if it's better than the already saved one, when feature flag is enabled.
return func (s *Service) saveLightClientUpdate(cfg *postBlockProcessConfig) {
} attestedRoot := cfg.roblock.Block().ParentRoot()
attestedBlock, err := s.getBlock(cfg.ctx, attestedRoot)
config := params.BeaconConfig()
if finalized.Epoch < config.AltairForkEpoch {
return
}
syncAggregate, err := signed.Block().Body().SyncAggregate()
if err != nil || syncAggregate == nil {
return
}
// LightClientFinalityUpdate needs super majority
if syncAggregate.SyncCommitteeBits.Count()*3 < config.SyncCommitteeSize*2 {
return
}
_, err = s.sendLightClientFinalityUpdate(ctx, signed, postState)
if err != nil { if err != nil {
log.WithError(err).Error("Failed to send light client finality update") log.WithError(err).Error("Saving light client update failed: Could not get attested block")
return
}
if attestedBlock == nil || attestedBlock.IsNil() {
log.Error("Saving light client update failed: Attested block is nil")
return
}
attestedState, err := s.cfg.StateGen.StateByRoot(cfg.ctx, attestedRoot)
if err != nil {
log.WithError(err).Error("Saving light client update failed: Could not get attested state")
return
}
if attestedState == nil || attestedState.IsNil() {
log.Error("Saving light client update failed: Attested state is nil")
return
}
finalizedRoot := attestedState.FinalizedCheckpoint().Root
finalizedBlock, err := s.getBlock(cfg.ctx, [32]byte(finalizedRoot))
if err != nil {
log.WithError(err).Error("Saving light client update failed: Could not get finalized block")
return
}
update, err := lightclient.NewLightClientUpdateFromBeaconState(
cfg.ctx,
s.CurrentSlot(),
cfg.postState,
cfg.roblock,
attestedState,
attestedBlock,
finalizedBlock,
)
if err != nil {
log.WithError(err).Error("Saving light client update failed: Could not create light client update")
return
}
period := slots.SyncCommitteePeriod(slots.ToEpoch(attestedState.Slot()))
oldUpdate, err := s.cfg.BeaconDB.LightClientUpdate(cfg.ctx, period)
if err != nil {
log.WithError(err).Error("Saving light client update failed: Could not get current light client update")
return
}
if oldUpdate == nil {
if err := s.cfg.BeaconDB.SaveLightClientUpdate(cfg.ctx, period, update); err != nil {
log.WithError(err).Error("Saving light client update failed: Could not save light client update")
} else {
log.WithField("period", period).Debug("Saving light client update: Saved new update")
}
return
}
isNewUpdateBetter, err := lightclient.IsBetterUpdate(update, oldUpdate)
if err != nil {
log.WithError(err).Error("Saving light client update failed: Could not compare light client updates")
return
}
if isNewUpdateBetter {
if err := s.cfg.BeaconDB.SaveLightClientUpdate(cfg.ctx, period, update); err != nil {
log.WithError(err).Error("Saving light client update failed: Could not save light client update")
} else {
log.WithField("period", period).Debug("Saving light client update: Saved new update")
}
} else { } else {
s.lastPublishedLightClientEpoch = finalized.Epoch log.WithField("period", period).Debug("Saving light client update: New update is not better than the current one. Skipping save.")
} }
} }
// sendLightClientFinalityUpdate sends a light client finality update notification to the state feed. // saveLightClientBootstrap saves a light client bootstrap for this block
func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed interfaces.ReadOnlySignedBeaconBlock, // when feature flag is enabled.
postState state.BeaconState) (int, error) { func (s *Service) saveLightClientBootstrap(cfg *postBlockProcessConfig) {
// Get attested state blockRoot := cfg.roblock.Root()
bootstrap, err := lightclient.NewLightClientBootstrapFromBeaconState(cfg.ctx, s.CurrentSlot(), cfg.postState, cfg.roblock)
if err != nil {
log.WithError(err).Error("Saving light client bootstrap failed: Could not create light client bootstrap")
return
}
err = s.cfg.BeaconDB.SaveLightClientBootstrap(cfg.ctx, blockRoot[:], bootstrap)
if err != nil {
log.WithError(err).Error("Saving light client bootstrap failed: Could not save light client bootstrap in DB")
}
}
func (s *Service) processLightClientFinalityUpdate(
ctx context.Context,
signed interfaces.ReadOnlySignedBeaconBlock,
postState state.BeaconState,
) error {
attestedRoot := signed.Block().ParentRoot() attestedRoot := signed.Block().ParentRoot()
attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot) attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "could not get attested block") return errors.Wrap(err, "could not get attested block")
} }
attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot) attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "could not get attested state") return errors.Wrap(err, "could not get attested state")
} }
// Get finalized block
var finalizedBlock interfaces.ReadOnlySignedBeaconBlock var finalizedBlock interfaces.ReadOnlySignedBeaconBlock
finalizedCheckPoint := attestedState.FinalizedCheckpoint() finalizedCheckPoint := attestedState.FinalizedCheckpoint()
if finalizedCheckPoint != nil { if finalizedCheckPoint != nil {
@@ -185,6 +242,7 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState( update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(
ctx, ctx,
postState.Slot(),
postState, postState,
signed, signed,
attestedState, attestedState,
@@ -193,38 +251,31 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
) )
if err != nil { if err != nil {
return 0, errors.Wrap(err, "could not create light client update") return errors.Wrap(err, "could not create light client finality update")
} }
// Return the result s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
result := &ethpbv2.LightClientFinalityUpdateWithVersion{
Version: ethpbv2.Version(signed.Version()),
Data: update,
}
// Send event
return s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.LightClientFinalityUpdate, Type: statefeed.LightClientFinalityUpdate,
Data: result, Data: update,
}), nil })
return nil
} }
// sendLightClientOptimisticUpdate sends a light client optimistic update notification to the state feed. func (s *Service) processLightClientOptimisticUpdate(ctx context.Context, signed interfaces.ReadOnlySignedBeaconBlock,
func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed interfaces.ReadOnlySignedBeaconBlock, postState state.BeaconState) error {
postState state.BeaconState) (int, error) {
// Get attested state
attestedRoot := signed.Block().ParentRoot() attestedRoot := signed.Block().ParentRoot()
attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot) attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "could not get attested block") return errors.Wrap(err, "could not get attested block")
} }
attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot) attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "could not get attested state") return errors.Wrap(err, "could not get attested state")
} }
update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState( update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(
ctx, ctx,
postState.Slot(),
postState, postState,
signed, signed,
attestedState, attestedState,
@@ -232,19 +283,15 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in
) )
if err != nil { if err != nil {
return 0, errors.Wrap(err, "could not create light client update") return errors.Wrap(err, "could not create light client optimistic update")
} }
// Return the result s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
result := &ethpbv2.LightClientOptimisticUpdateWithVersion{
Version: ethpbv2.Version(signed.Version()),
Data: update,
}
return s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.LightClientOptimisticUpdate, Type: statefeed.LightClientOptimisticUpdate,
Data: result, Data: update,
}), nil })
return nil
} }
// updateCachesPostBlockProcessing updates the next slot cache and handles the epoch // updateCachesPostBlockProcessing updates the next slot cache and handles the epoch

View File

@@ -40,6 +40,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/require" "github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util" "github.com/prysmaticlabs/prysm/v5/testing/util"
prysmTime "github.com/prysmaticlabs/prysm/v5/time" prysmTime "github.com/prysmaticlabs/prysm/v5/time"
"github.com/prysmaticlabs/prysm/v5/time/slots"
logTest "github.com/sirupsen/logrus/hooks/test" logTest "github.com/sirupsen/logrus/hooks/test"
) )
@@ -2502,3 +2503,290 @@ func fakeResult(missing []uint64) map[uint64]struct{} {
} }
return r return r
} }
func TestSaveLightClientUpdate(t *testing.T) {
s, tr := minimalTestService(t)
ctx := tr.ctx
t.Run("Altair", func(t *testing.T) {
featCfg := &features.Flags{}
featCfg.EnableLightClient = true
reset := features.InitWithReset(featCfg)
l := util.NewTestLightClient(t).SetupTestAltair()
s.genesisTime = time.Unix(time.Now().Unix()-(int64(params.BeaconConfig().AltairForkEpoch)*int64(params.BeaconConfig().SlotsPerEpoch)*int64(params.BeaconConfig().SecondsPerSlot)), 0)
err := s.cfg.BeaconDB.SaveBlock(ctx, l.AttestedBlock)
require.NoError(t, err)
attestedBlockRoot, err := l.AttestedBlock.Block().HashTreeRoot()
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.AttestedState, attestedBlockRoot)
require.NoError(t, err)
currentBlockRoot, err := l.Block.Block().HashTreeRoot()
require.NoError(t, err)
roblock, err := consensusblocks.NewROBlockWithRoot(l.Block, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, roblock)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.State, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, l.FinalizedBlock)
require.NoError(t, err)
cfg := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
postState: l.State,
isValidPayload: true,
}
s.saveLightClientUpdate(cfg)
// Check that the light client update is saved
period := slots.SyncCommitteePeriod(slots.ToEpoch(l.AttestedState.Slot()))
u, err := s.cfg.BeaconDB.LightClientUpdate(ctx, period)
require.NoError(t, err)
require.NotNil(t, u)
attestedStateRoot, err := l.AttestedState.HashTreeRoot(ctx)
require.NoError(t, err)
require.Equal(t, attestedStateRoot, [32]byte(u.AttestedHeader().Beacon().StateRoot))
require.Equal(t, u.Version(), version.Altair)
reset()
})
t.Run("Capella", func(t *testing.T) {
featCfg := &features.Flags{}
featCfg.EnableLightClient = true
reset := features.InitWithReset(featCfg)
l := util.NewTestLightClient(t).SetupTestCapella(false)
s.genesisTime = time.Unix(time.Now().Unix()-(int64(params.BeaconConfig().CapellaForkEpoch)*int64(params.BeaconConfig().SlotsPerEpoch)*int64(params.BeaconConfig().SecondsPerSlot)), 0)
err := s.cfg.BeaconDB.SaveBlock(ctx, l.AttestedBlock)
require.NoError(t, err)
attestedBlockRoot, err := l.AttestedBlock.Block().HashTreeRoot()
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.AttestedState, attestedBlockRoot)
require.NoError(t, err)
currentBlockRoot, err := l.Block.Block().HashTreeRoot()
require.NoError(t, err)
roblock, err := consensusblocks.NewROBlockWithRoot(l.Block, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, roblock)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.State, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, l.FinalizedBlock)
require.NoError(t, err)
cfg := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
postState: l.State,
isValidPayload: true,
}
s.saveLightClientUpdate(cfg)
// Check that the light client update is saved
period := slots.SyncCommitteePeriod(slots.ToEpoch(l.AttestedState.Slot()))
u, err := s.cfg.BeaconDB.LightClientUpdate(ctx, period)
require.NoError(t, err)
require.NotNil(t, u)
attestedStateRoot, err := l.AttestedState.HashTreeRoot(ctx)
require.NoError(t, err)
require.Equal(t, attestedStateRoot, [32]byte(u.AttestedHeader().Beacon().StateRoot))
require.Equal(t, u.Version(), version.Capella)
reset()
})
t.Run("Deneb", func(t *testing.T) {
featCfg := &features.Flags{}
featCfg.EnableLightClient = true
reset := features.InitWithReset(featCfg)
l := util.NewTestLightClient(t).SetupTestDeneb(false)
s.genesisTime = time.Unix(time.Now().Unix()-(int64(params.BeaconConfig().DenebForkEpoch)*int64(params.BeaconConfig().SlotsPerEpoch)*int64(params.BeaconConfig().SecondsPerSlot)), 0)
err := s.cfg.BeaconDB.SaveBlock(ctx, l.AttestedBlock)
require.NoError(t, err)
attestedBlockRoot, err := l.AttestedBlock.Block().HashTreeRoot()
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.AttestedState, attestedBlockRoot)
require.NoError(t, err)
currentBlockRoot, err := l.Block.Block().HashTreeRoot()
require.NoError(t, err)
roblock, err := consensusblocks.NewROBlockWithRoot(l.Block, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, roblock)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.State, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, l.FinalizedBlock)
require.NoError(t, err)
cfg := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
postState: l.State,
isValidPayload: true,
}
s.saveLightClientUpdate(cfg)
// Check that the light client update is saved
period := slots.SyncCommitteePeriod(slots.ToEpoch(l.AttestedState.Slot()))
u, err := s.cfg.BeaconDB.LightClientUpdate(ctx, period)
require.NoError(t, err)
require.NotNil(t, u)
attestedStateRoot, err := l.AttestedState.HashTreeRoot(ctx)
require.NoError(t, err)
require.Equal(t, attestedStateRoot, [32]byte(u.AttestedHeader().Beacon().StateRoot))
require.Equal(t, u.Version(), version.Deneb)
reset()
})
}
func TestSaveLightClientBootstrap(t *testing.T) {
s, tr := minimalTestService(t)
ctx := tr.ctx
t.Run("Altair", func(t *testing.T) {
featCfg := &features.Flags{}
featCfg.EnableLightClient = true
reset := features.InitWithReset(featCfg)
l := util.NewTestLightClient(t).SetupTestAltair()
s.genesisTime = time.Unix(time.Now().Unix()-(int64(params.BeaconConfig().AltairForkEpoch)*int64(params.BeaconConfig().SlotsPerEpoch)*int64(params.BeaconConfig().SecondsPerSlot)), 0)
currentBlockRoot, err := l.Block.Block().HashTreeRoot()
require.NoError(t, err)
roblock, err := consensusblocks.NewROBlockWithRoot(l.Block, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, roblock)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.State, currentBlockRoot)
require.NoError(t, err)
cfg := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
postState: l.State,
isValidPayload: true,
}
s.saveLightClientBootstrap(cfg)
// Check that the light client bootstrap is saved
b, err := s.cfg.BeaconDB.LightClientBootstrap(ctx, currentBlockRoot[:])
require.NoError(t, err)
require.NotNil(t, b)
stateRoot, err := l.State.HashTreeRoot(ctx)
require.NoError(t, err)
require.Equal(t, stateRoot, [32]byte(b.Header().Beacon().StateRoot))
require.Equal(t, b.Version(), version.Altair)
reset()
})
t.Run("Capella", func(t *testing.T) {
featCfg := &features.Flags{}
featCfg.EnableLightClient = true
reset := features.InitWithReset(featCfg)
l := util.NewTestLightClient(t).SetupTestCapella(false)
s.genesisTime = time.Unix(time.Now().Unix()-(int64(params.BeaconConfig().CapellaForkEpoch)*int64(params.BeaconConfig().SlotsPerEpoch)*int64(params.BeaconConfig().SecondsPerSlot)), 0)
currentBlockRoot, err := l.Block.Block().HashTreeRoot()
require.NoError(t, err)
roblock, err := consensusblocks.NewROBlockWithRoot(l.Block, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, roblock)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.State, currentBlockRoot)
require.NoError(t, err)
cfg := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
postState: l.State,
isValidPayload: true,
}
s.saveLightClientBootstrap(cfg)
// Check that the light client bootstrap is saved
b, err := s.cfg.BeaconDB.LightClientBootstrap(ctx, currentBlockRoot[:])
require.NoError(t, err)
require.NotNil(t, b)
stateRoot, err := l.State.HashTreeRoot(ctx)
require.NoError(t, err)
require.Equal(t, stateRoot, [32]byte(b.Header().Beacon().StateRoot))
require.Equal(t, b.Version(), version.Capella)
reset()
})
t.Run("Deneb", func(t *testing.T) {
featCfg := &features.Flags{}
featCfg.EnableLightClient = true
reset := features.InitWithReset(featCfg)
l := util.NewTestLightClient(t).SetupTestDeneb(false)
s.genesisTime = time.Unix(time.Now().Unix()-(int64(params.BeaconConfig().DenebForkEpoch)*int64(params.BeaconConfig().SlotsPerEpoch)*int64(params.BeaconConfig().SecondsPerSlot)), 0)
currentBlockRoot, err := l.Block.Block().HashTreeRoot()
require.NoError(t, err)
roblock, err := consensusblocks.NewROBlockWithRoot(l.Block, currentBlockRoot)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveBlock(ctx, roblock)
require.NoError(t, err)
err = s.cfg.BeaconDB.SaveState(ctx, l.State, currentBlockRoot)
require.NoError(t, err)
cfg := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
postState: l.State,
isValidPayload: true,
}
s.saveLightClientBootstrap(cfg)
// Check that the light client bootstrap is saved
b, err := s.cfg.BeaconDB.LightClientBootstrap(ctx, currentBlockRoot[:])
require.NoError(t, err)
require.NotNil(t, b)
stateRoot, err := l.State.HashTreeRoot(ctx)
require.NoError(t, err)
require.Equal(t, stateRoot, [32]byte(b.Header().Beacon().StateRoot))
require.Equal(t, b.Version(), version.Deneb)
reset()
})
}

View File

@@ -10,7 +10,6 @@ import (
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -87,9 +86,7 @@ func TestProcessAttestations_Ok(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot)) require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
attsToSave := make([]ethpb.Att, len(atts)) attsToSave := make([]ethpb.Att, len(atts))
for i, a := range atts { copy(attsToSave, atts)
attsToSave[i] = a
}
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave)) require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave))
service.processAttestations(ctx, 0) service.processAttestations(ctx, 0)
require.Equal(t, 0, len(service.cfg.AttPool.ForkchoiceAttestations())) require.Equal(t, 0, len(service.cfg.AttPool.ForkchoiceAttestations()))
@@ -119,7 +116,7 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
postState, err := service.validateStateTransition(ctx, preState, wsb) postState, err := service.validateStateTransition(ctx, preState, wsb)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, service.savePostStateInfo(ctx, tRoot, wsb, postState)) require.NoError(t, service.savePostStateInfo(ctx, tRoot, wsb, postState))
roblock, err := consensus_blocks.NewROBlockWithRoot(wsb, tRoot) roblock, err := blocks.NewROBlockWithRoot(wsb, tRoot)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, roblock, [32]byte{}, postState, false})) require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, roblock, [32]byte{}, postState, false}))
copied, err = service.cfg.StateGen.StateByRoot(ctx, tRoot) copied, err = service.cfg.StateGen.StateByRoot(ctx, tRoot)
@@ -131,9 +128,7 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
atts, err := util.GenerateAttestations(copied, pks, 1, 1, false) atts, err := util.GenerateAttestations(copied, pks, 1, 1, false)
require.NoError(t, err) require.NoError(t, err)
attsToSave := make([]ethpb.Att, len(atts)) attsToSave := make([]ethpb.Att, len(atts))
for i, a := range atts { copy(attsToSave, atts)
attsToSave[i] = a
}
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave)) require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave))
// Verify the target is in forkchoice // Verify the target is in forkchoice
require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].GetData().BeaconBlockRoot))) require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].GetData().BeaconBlockRoot)))
@@ -181,7 +176,7 @@ func TestService_UpdateHead_NoAtts(t *testing.T) {
postState, err := service.validateStateTransition(ctx, preState, wsb) postState, err := service.validateStateTransition(ctx, preState, wsb)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, service.savePostStateInfo(ctx, tRoot, wsb, postState)) require.NoError(t, service.savePostStateInfo(ctx, tRoot, wsb, postState))
roblock, err := consensus_blocks.NewROBlockWithRoot(wsb, tRoot) roblock, err := blocks.NewROBlockWithRoot(wsb, tRoot)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, roblock, [32]byte{}, postState, false})) require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, roblock, [32]byte{}, postState, false}))
require.Equal(t, 2, fcs.NodeCount()) require.Equal(t, 2, fcs.NodeCount())

View File

@@ -17,8 +17,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/features" "github.com/prysmaticlabs/prysm/v5/config/features"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
@@ -85,7 +83,7 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
} }
currentCheckpoints := s.saveCurrentCheckpoints(preState) currentCheckpoints := s.saveCurrentCheckpoints(preState)
roblock, err := consensus_blocks.NewROBlockWithRoot(blockCopy, blockRoot) roblock, err := blocks.NewROBlockWithRoot(blockCopy, blockRoot)
if err != nil { if err != nil {
return err return err
} }
@@ -190,7 +188,7 @@ func (s *Service) updateCheckpoints(
func (s *Service) validateExecutionAndConsensus( func (s *Service) validateExecutionAndConsensus(
ctx context.Context, ctx context.Context,
preState state.BeaconState, preState state.BeaconState,
block consensusblocks.ROBlock, block blocks.ROBlock,
) (state.BeaconState, bool, error) { ) (state.BeaconState, bool, error) {
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState) preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
if err != nil { if err != nil {
@@ -560,7 +558,7 @@ func (s *Service) sendBlockAttestationsToSlasher(signed interfaces.ReadOnlySigne
} }
// validateExecutionOnBlock notifies the engine of the incoming block execution payload and returns true if the payload is valid // validateExecutionOnBlock notifies the engine of the incoming block execution payload and returns true if the payload is valid
func (s *Service) validateExecutionOnBlock(ctx context.Context, ver int, header interfaces.ExecutionData, block consensusblocks.ROBlock) (bool, error) { func (s *Service) validateExecutionOnBlock(ctx context.Context, ver int, header interfaces.ExecutionData, block blocks.ROBlock) (bool, error) {
isValidPayload, err := s.notifyNewPayload(ctx, ver, header, block) isValidPayload, err := s.notifyNewPayload(ctx, ver, header, block)
if err != nil { if err != nil {
s.cfg.ForkChoiceStore.Lock() s.cfg.ForkChoiceStore.Lock()

View File

@@ -36,9 +36,7 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -49,25 +47,24 @@ import (
// Service represents a service that handles the internal // Service represents a service that handles the internal
// logic of managing the full PoS beacon chain. // logic of managing the full PoS beacon chain.
type Service struct { type Service struct {
cfg *config cfg *config
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
genesisTime time.Time genesisTime time.Time
head *head head *head
headLock sync.RWMutex headLock sync.RWMutex
originBlockRoot [32]byte // genesis root, or weak subjectivity checkpoint root, depending on how the node is initialized originBlockRoot [32]byte // genesis root, or weak subjectivity checkpoint root, depending on how the node is initialized
boundaryRoots [][32]byte boundaryRoots [][32]byte
checkpointStateCache *cache.CheckpointStateCache checkpointStateCache *cache.CheckpointStateCache
initSyncBlocks map[[32]byte]interfaces.ReadOnlySignedBeaconBlock initSyncBlocks map[[32]byte]interfaces.ReadOnlySignedBeaconBlock
initSyncBlocksLock sync.RWMutex initSyncBlocksLock sync.RWMutex
wsVerifier *WeakSubjectivityVerifier wsVerifier *WeakSubjectivityVerifier
clockSetter startup.ClockSetter clockSetter startup.ClockSetter
clockWaiter startup.ClockWaiter clockWaiter startup.ClockWaiter
syncComplete chan struct{} syncComplete chan struct{}
blobNotifiers *blobNotifierMap blobNotifiers *blobNotifierMap
blockBeingSynced *currentlySyncingBlock blockBeingSynced *currentlySyncingBlock
blobStorage *filesystem.BlobStorage blobStorage *filesystem.BlobStorage
lastPublishedLightClientEpoch primitives.Epoch
} }
// config options for the service. // config options for the service.
@@ -308,7 +305,7 @@ func (s *Service) StartFromSavedState(saved state.BeaconState) error {
if err != nil { if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint block") return errors.Wrap(err, "could not get finalized checkpoint block")
} }
roblock, err := consensus_blocks.NewROBlockWithRoot(finalizedBlock, fRoot) roblock, err := blocks.NewROBlockWithRoot(finalizedBlock, fRoot)
if err != nil { if err != nil {
return err return err
} }
@@ -524,7 +521,7 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState state.Beacon
s.cfg.ForkChoiceStore.Lock() s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock() defer s.cfg.ForkChoiceStore.Unlock()
gb, err := consensus_blocks.NewROBlockWithRoot(genesisBlk, genesisBlkRoot) gb, err := blocks.NewROBlockWithRoot(genesisBlk, genesisBlkRoot)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -6,19 +6,22 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client", importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//beacon-chain/execution:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library", "//config/fieldparams:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types:go_default_library", "//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library", "//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library", "//consensus-types/interfaces:go_default_library",
"//consensus-types/light-client:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/ssz:go_default_library", "//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//proto/eth/v2:go_default_library",
"//runtime/version:go_default_library", "//runtime/version:go_default_library",
"//time/slots:go_default_library", "//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library", "@com_github_pkg_errors//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
], ],
) )
@@ -32,6 +35,7 @@ go_test(
"//consensus-types/blocks:go_default_library", "//consensus-types/blocks:go_default_library",
"//encoding/ssz:go_default_library", "//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/require:go_default_library", "//testing/require:go_default_library",
"//testing/util:go_default_library", "//testing/util:go_default_library",
"@com_github_pkg_errors//:go_default_library", "@com_github_pkg_errors//:go_default_library",

View File

@@ -4,87 +4,74 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"reflect"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
light_client "github.com/prysmaticlabs/prysm/v5/consensus-types/light-client"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz" "github.com/prysmaticlabs/prysm/v5/encoding/ssz"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots" "github.com/prysmaticlabs/prysm/v5/time/slots"
"google.golang.org/protobuf/proto"
) )
const (
FinalityBranchNumOfLeaves = 6
executionBranchNumOfLeaves = 4
)
func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate {
finalityUpdate := &ethpbv2.LightClientFinalityUpdate{
AttestedHeader: update.AttestedHeader,
FinalizedHeader: update.FinalizedHeader,
FinalityBranch: update.FinalityBranch,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
return finalityUpdate
}
func createLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate {
optimisticUpdate := &ethpbv2.LightClientOptimisticUpdate{
AttestedHeader: update.AttestedHeader,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
return optimisticUpdate
}
func NewLightClientFinalityUpdateFromBeaconState( func NewLightClientFinalityUpdateFromBeaconState(
ctx context.Context, ctx context.Context,
currentSlot primitives.Slot,
state state.BeaconState, state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock, block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState, attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock, attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock, finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*ethpbv2.LightClientFinalityUpdate, error) { ) (interfaces.LightClientFinalityUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock) update, err := NewLightClientUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, finalizedBlock)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return createLightClientFinalityUpdate(update), nil return light_client.NewFinalityUpdateFromUpdate(update)
} }
func NewLightClientOptimisticUpdateFromBeaconState( func NewLightClientOptimisticUpdateFromBeaconState(
ctx context.Context, ctx context.Context,
currentSlot primitives.Slot,
state state.BeaconState, state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock, block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState, attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock, attestedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*ethpbv2.LightClientOptimisticUpdate, error) { ) (interfaces.LightClientOptimisticUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, nil) update, err := NewLightClientUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return createLightClientOptimisticUpdate(update), nil return light_client.NewOptimisticUpdateFromUpdate(update)
} }
// To form a LightClientUpdate, the following historical states and blocks are needed:
// - state: the post state of any block with a post-Altair parent block
// - block: the corresponding block
// - attested_state: the post state of attested_block
// - attested_block: the block referred to by block.parent_root
// - finalized_block: the block referred to by attested_state.finalized_checkpoint.root,
// if locally available (may be unavailable, e.g., when using checkpoint sync, or if it was pruned locally)
func NewLightClientUpdateFromBeaconState( func NewLightClientUpdateFromBeaconState(
ctx context.Context, ctx context.Context,
currentSlot primitives.Slot,
state state.BeaconState, state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock, block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState, attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock, attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) { finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (interfaces.LightClientUpdate, error) {
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH // assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
attestedEpoch := slots.ToEpoch(attestedState.Slot()) attestedEpoch := slots.ToEpoch(attestedState.Slot())
if attestedEpoch < params.BeaconConfig().AltairForkEpoch { if attestedEpoch < params.BeaconConfig().AltairForkEpoch {
@@ -129,7 +116,11 @@ func NewLightClientUpdateFromBeaconState(
// assert attested_state.slot == attested_state.latest_block_header.slot // assert attested_state.slot == attested_state.latest_block_header.slot
if attestedState.Slot() != attestedState.LatestBlockHeader().Slot { if attestedState.Slot() != attestedState.LatestBlockHeader().Slot {
return nil, fmt.Errorf("attested state slot %d not equal to attested latest block header slot %d", attestedState.Slot(), attestedState.LatestBlockHeader().Slot) return nil, fmt.Errorf(
"attested state slot %d not equal to attested latest block header slot %d",
attestedState.Slot(),
attestedState.LatestBlockHeader().Slot,
)
} }
// attested_header = attested_state.latest_block_header.copy() // attested_header = attested_state.latest_block_header.copy()
@@ -153,46 +144,58 @@ func NewLightClientUpdateFromBeaconState(
} }
// assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root // assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root
if attestedHeaderRoot != block.Block().ParentRoot() || attestedHeaderRoot != attestedBlockRoot { if attestedHeaderRoot != block.Block().ParentRoot() || attestedHeaderRoot != attestedBlockRoot {
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x or attested block root %#x", attestedHeaderRoot, block.Block().ParentRoot(), attestedBlockRoot) return nil, fmt.Errorf(
"attested header root %#x not equal to block parent root %#x or attested block root %#x",
attestedHeaderRoot,
block.Block().ParentRoot(),
attestedBlockRoot,
)
} }
// update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot) // update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot)
updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(attestedBlock.Block().Slot())) updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(attestedBlock.Block().Slot()))
// update = LightClientUpdate() // update = LightClientUpdate()
result, err := createDefaultLightClientUpdate() result, err := CreateDefaultLightClientUpdate(currentSlot, attestedState)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not create default light client update") return nil, errors.Wrap(err, "could not create default light client update")
} }
// update.attested_header = block_to_light_client_header(attested_block) // update.attested_header = block_to_light_client_header(attested_block)
attestedLightClientHeader, err := BlockToLightClientHeader(attestedBlock) attestedLightClientHeader, err := BlockToLightClientHeader(ctx, currentSlot, attestedBlock)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get attested light client header") return nil, errors.Wrap(err, "could not get attested light client header")
} }
result.AttestedHeader = attestedLightClientHeader if err = result.SetAttestedHeader(attestedLightClientHeader); err != nil {
return nil, errors.Wrap(err, "could not set attested header")
}
// if update_attested_period == update_signature_period // if update_attested_period == update_signature_period
if updateAttestedPeriod == updateSignaturePeriod { if updateAttestedPeriod == updateSignaturePeriod {
// update.next_sync_committee = attested_state.next_sync_committee
tempNextSyncCommittee, err := attestedState.NextSyncCommittee() tempNextSyncCommittee, err := attestedState.NextSyncCommittee()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee") return nil, errors.Wrap(err, "could not get next sync committee")
} }
nextSyncCommittee := &ethpbv2.SyncCommittee{ nextSyncCommittee := &pb.SyncCommittee{
Pubkeys: tempNextSyncCommittee.Pubkeys, Pubkeys: tempNextSyncCommittee.Pubkeys,
AggregatePubkey: tempNextSyncCommittee.AggregatePubkey, AggregatePubkey: tempNextSyncCommittee.AggregatePubkey,
} }
result.SetNextSyncCommittee(nextSyncCommittee)
// update.next_sync_committee_branch = NextSyncCommitteeBranch(
// compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot)))
nextSyncCommitteeBranch, err := attestedState.NextSyncCommitteeProof(ctx) nextSyncCommitteeBranch, err := attestedState.NextSyncCommitteeProof(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee proof") return nil, errors.Wrap(err, "could not get next sync committee proof")
} }
if attestedBlock.Version() >= version.Electra {
// update.next_sync_committee = attested_state.next_sync_committee if err = result.SetNextSyncCommitteeBranch(nextSyncCommitteeBranch); err != nil {
result.NextSyncCommittee = nextSyncCommittee return nil, errors.Wrap(err, "could not set next sync committee branch")
}
// update.next_sync_committee_branch = NextSyncCommitteeBranch( } else if err = result.SetNextSyncCommitteeBranch(nextSyncCommitteeBranch); err != nil {
// compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot))) return nil, errors.Wrap(err, "could not set next sync committee branch")
result.NextSyncCommitteeBranch = nextSyncCommitteeBranch }
} }
// if finalized_block is not None // if finalized_block is not None
@@ -200,11 +203,13 @@ func NewLightClientUpdateFromBeaconState(
// if finalized_block.message.slot != GENESIS_SLOT // if finalized_block.message.slot != GENESIS_SLOT
if finalizedBlock.Block().Slot() != 0 { if finalizedBlock.Block().Slot() != 0 {
// update.finalized_header = block_to_light_client_header(finalized_block) // update.finalized_header = block_to_light_client_header(finalized_block)
finalizedLightClientHeader, err := BlockToLightClientHeader(finalizedBlock) finalizedLightClientHeader, err := BlockToLightClientHeader(ctx, currentSlot, finalizedBlock)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get finalized light client header") return nil, errors.Wrap(err, "could not get finalized light client header")
} }
result.FinalizedHeader = finalizedLightClientHeader if err = result.SetFinalizedHeader(finalizedLightClientHeader); err != nil {
return nil, errors.Wrap(err, "could not set finalized header")
}
} else { } else {
// assert attested_state.finalized_checkpoint.root == Bytes32() // assert attested_state.finalized_checkpoint.root == Bytes32()
if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) { if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) {
@@ -218,49 +223,120 @@ func NewLightClientUpdateFromBeaconState(
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get finalized root proof") return nil, errors.Wrap(err, "could not get finalized root proof")
} }
result.FinalityBranch = finalityBranch if err = result.SetFinalityBranch(finalityBranch); err != nil {
return nil, errors.Wrap(err, "could not set finality branch")
}
} }
// update.sync_aggregate = block.message.body.sync_aggregate // update.sync_aggregate = block.message.body.sync_aggregate
result.SyncAggregate = &ethpbv1.SyncAggregate{ result.SetSyncAggregate(&pb.SyncAggregate{
SyncCommitteeBits: syncAggregate.SyncCommitteeBits, SyncCommitteeBits: syncAggregate.SyncCommitteeBits,
SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature, SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature,
} })
// update.signature_slot = block.message.slot // update.signature_slot = block.message.slot
result.SignatureSlot = block.Block().Slot() result.SetSignatureSlot(block.Block().Slot())
return result, nil return result, nil
} }
func createDefaultLightClientUpdate() (*ethpbv2.LightClientUpdate, error) { func CreateDefaultLightClientUpdate(currentSlot primitives.Slot, attestedState state.BeaconState) (interfaces.LightClientUpdate, error) {
currentEpoch := slots.ToEpoch(currentSlot)
syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize
pubKeys := make([][]byte, syncCommitteeSize) pubKeys := make([][]byte, syncCommitteeSize)
for i := uint64(0); i < syncCommitteeSize; i++ { for i := uint64(0); i < syncCommitteeSize; i++ {
pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength) pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength)
} }
nextSyncCommittee := &ethpbv2.SyncCommittee{ nextSyncCommittee := &pb.SyncCommittee{
Pubkeys: pubKeys, Pubkeys: pubKeys,
AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength), AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength),
} }
nextSyncCommitteeBranch := make([][]byte, fieldparams.SyncCommitteeBranchDepth)
for i := 0; i < fieldparams.SyncCommitteeBranchDepth; i++ { var nextSyncCommitteeBranch [][]byte
if attestedState.Version() >= version.Electra {
nextSyncCommitteeBranch = make([][]byte, fieldparams.SyncCommitteeBranchDepthElectra)
} else {
nextSyncCommitteeBranch = make([][]byte, fieldparams.SyncCommitteeBranchDepth)
}
for i := 0; i < len(nextSyncCommitteeBranch); i++ {
nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength) nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength)
} }
executionBranch := make([][]byte, executionBranchNumOfLeaves)
for i := 0; i < executionBranchNumOfLeaves; i++ { executionBranch := make([][]byte, fieldparams.ExecutionBranchDepth)
for i := 0; i < fieldparams.ExecutionBranchDepth; i++ {
executionBranch[i] = make([]byte, 32) executionBranch[i] = make([]byte, 32)
} }
finalityBranch := make([][]byte, FinalityBranchNumOfLeaves)
for i := 0; i < FinalityBranchNumOfLeaves; i++ { var finalityBranch [][]byte
if attestedState.Version() >= version.Electra {
finalityBranch = make([][]byte, fieldparams.FinalityBranchDepthElectra)
} else {
finalityBranch = make([][]byte, fieldparams.FinalityBranchDepth)
}
for i := 0; i < len(finalityBranch); i++ {
finalityBranch[i] = make([]byte, 32) finalityBranch[i] = make([]byte, 32)
} }
return &ethpbv2.LightClientUpdate{ var m proto.Message
NextSyncCommittee: nextSyncCommittee, if currentEpoch < params.BeaconConfig().CapellaForkEpoch {
NextSyncCommitteeBranch: nextSyncCommitteeBranch, m = &pb.LightClientUpdateAltair{
FinalityBranch: finalityBranch, AttestedHeader: &pb.LightClientHeaderAltair{
}, nil Beacon: &pb.BeaconBlockHeader{},
},
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalityBranch: finalityBranch,
}
} else if currentEpoch < params.BeaconConfig().DenebForkEpoch {
m = &pb.LightClientUpdateCapella{
AttestedHeader: &pb.LightClientHeaderCapella{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderCapella{},
ExecutionBranch: executionBranch,
},
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalityBranch: finalityBranch,
}
} else if currentEpoch < params.BeaconConfig().ElectraForkEpoch {
m = &pb.LightClientUpdateDeneb{
AttestedHeader: &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderDeneb{},
ExecutionBranch: executionBranch,
},
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalityBranch: finalityBranch,
}
} else {
if attestedState.Version() >= version.Electra {
m = &pb.LightClientUpdateElectra{
AttestedHeader: &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderDeneb{},
ExecutionBranch: executionBranch,
},
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalityBranch: finalityBranch,
}
} else {
m = &pb.LightClientUpdateDeneb{
AttestedHeader: &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderDeneb{},
ExecutionBranch: executionBranch,
},
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalityBranch: finalityBranch,
}
}
}
return light_client.NewWrappedUpdate(m)
} }
func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) { func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) {
@@ -299,48 +375,14 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
return withdrawalsRoot, nil return withdrawalsRoot, nil
} }
func BlockToLightClientHeader(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderContainer, error) { func BlockToLightClientHeader(
switch block.Version() { ctx context.Context,
case version.Altair, version.Bellatrix: currentSlot primitives.Slot,
altairHeader, err := blockToLightClientHeaderAltair(block) block interfaces.ReadOnlySignedBeaconBlock,
if err != nil { ) (interfaces.LightClientHeader, error) {
return nil, errors.Wrap(err, "could not get header") var m proto.Message
} currentEpoch := slots.ToEpoch(currentSlot)
return &ethpbv2.LightClientHeaderContainer{ blockEpoch := slots.ToEpoch(block.Block().Slot())
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: altairHeader,
},
}, nil
case version.Capella:
capellaHeader, err := blockToLightClientHeaderCapella(context.Background(), block)
if err != nil {
return nil, errors.Wrap(err, "could not get capella header")
}
return &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: capellaHeader,
},
}, nil
case version.Deneb, version.Electra:
denebHeader, err := blockToLightClientHeaderDeneb(context.Background(), block)
if err != nil {
return nil, errors.Wrap(err, "could not get header")
}
return &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: denebHeader,
},
}, nil
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Version()))
}
}
func blockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeader, error) {
if block.Version() < version.Altair {
return nil, fmt.Errorf("block version is %s instead of Altair", version.String(block.Version()))
}
parentRoot := block.Block().ParentRoot() parentRoot := block.Block().ParentRoot()
stateRoot := block.Block().StateRoot() stateRoot := block.Block().StateRoot()
bodyRoot, err := block.Block().Body().HashTreeRoot() bodyRoot, err := block.Block().Body().HashTreeRoot()
@@ -348,147 +390,431 @@ func blockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock)
return nil, errors.Wrap(err, "could not get body root") return nil, errors.Wrap(err, "could not get body root")
} }
return &ethpbv2.LightClientHeader{ if currentEpoch < params.BeaconConfig().CapellaForkEpoch {
Beacon: &ethpbv1.BeaconBlockHeader{ m = &pb.LightClientHeaderAltair{
Slot: block.Block().Slot(), Beacon: &pb.BeaconBlockHeader{
ProposerIndex: block.Block().ProposerIndex(), Slot: block.Block().Slot(),
ParentRoot: parentRoot[:], ProposerIndex: block.Block().ProposerIndex(),
StateRoot: stateRoot[:], ParentRoot: parentRoot[:],
BodyRoot: bodyRoot[:], StateRoot: stateRoot[:],
}, BodyRoot: bodyRoot[:],
}, nil },
}
} else if currentEpoch < params.BeaconConfig().DenebForkEpoch {
var payloadHeader *enginev1.ExecutionPayloadHeaderCapella
var payloadProof [][]byte
if blockEpoch < params.BeaconConfig().CapellaForkEpoch {
payloadHeader = &enginev1.ExecutionPayloadHeaderCapella{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: make([]byte, fieldparams.RootLength),
ExtraData: make([]byte, 0),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
TransactionsRoot: make([]byte, fieldparams.RootLength),
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
}
payloadProof = emptyPayloadProof()
} else {
payload, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := ComputeTransactionsRoot(payload)
if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
withdrawalsRoot, err := ComputeWithdrawalsRoot(payload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
payloadHeader = &enginev1.ExecutionPayloadHeaderCapella{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
payloadProof, err = blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
}
m = &pb.LightClientHeaderCapella{
Beacon: &pb.BeaconBlockHeader{
Slot: block.Block().Slot(),
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:],
StateRoot: stateRoot[:],
BodyRoot: bodyRoot[:],
},
Execution: payloadHeader,
ExecutionBranch: payloadProof,
}
} else {
var payloadHeader *enginev1.ExecutionPayloadHeaderDeneb
var payloadProof [][]byte
if blockEpoch < params.BeaconConfig().CapellaForkEpoch {
var ok bool
p, err := execution.EmptyExecutionPayload(version.Deneb)
if err != nil {
return nil, errors.Wrap(err, "could not get payload header")
}
payloadHeader, ok = p.(*enginev1.ExecutionPayloadHeaderDeneb)
if !ok {
return nil, errors.Wrapf(err, "payload header type %T is not %T", payloadHeader, &enginev1.ExecutionPayloadHeaderDeneb{})
}
payloadProof = emptyPayloadProof()
} else {
payload, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := ComputeTransactionsRoot(payload)
if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
withdrawalsRoot, err := ComputeWithdrawalsRoot(payload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
var blobGasUsed uint64
var excessBlobGas uint64
if blockEpoch >= params.BeaconConfig().DenebForkEpoch {
blobGasUsed, err = payload.BlobGasUsed()
if err != nil {
return nil, errors.Wrap(err, "could not get blob gas used")
}
excessBlobGas, err = payload.ExcessBlobGas()
if err != nil {
return nil, errors.Wrap(err, "could not get excess blob gas")
}
}
payloadHeader = &enginev1.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
BlobGasUsed: blobGasUsed,
ExcessBlobGas: excessBlobGas,
}
payloadProof, err = blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
}
m = &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{
Slot: block.Block().Slot(),
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:],
StateRoot: stateRoot[:],
BodyRoot: bodyRoot[:],
},
Execution: payloadHeader,
ExecutionBranch: payloadProof,
}
}
return light_client.NewWrappedHeader(m)
} }
func blockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderCapella, error) { func emptyPayloadProof() [][]byte {
if block.Version() < version.Capella { branch := interfaces.LightClientExecutionBranch{}
return nil, fmt.Errorf("block version is %s instead of Capella", version.String(block.Version())) proof := make([][]byte, len(branch))
for i, b := range branch {
proof[i] = b[:]
} }
return proof
payload, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := ComputeTransactionsRoot(payload)
if err != nil {
return nil, err
}
withdrawalsRoot, err := ComputeWithdrawalsRoot(payload)
if err != nil {
return nil, err
}
executionHeader := &v11.ExecutionPayloadHeaderCapella{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
parentRoot := block.Block().ParentRoot()
stateRoot := block.Block().StateRoot()
bodyRoot, err := block.Block().Body().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get body root")
}
return &ethpbv2.LightClientHeaderCapella{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: block.Block().Slot(),
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:],
StateRoot: stateRoot[:],
BodyRoot: bodyRoot[:],
},
Execution: executionHeader,
ExecutionBranch: executionPayloadProof,
}, nil
} }
func blockToLightClientHeaderDeneb(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderDeneb, error) { func HasRelevantSyncCommittee(update interfaces.LightClientUpdate) (bool, error) {
if block.Version() < version.Deneb { if update.Version() >= version.Electra {
return nil, fmt.Errorf("block version is %s instead of Deneb/Electra", version.String(block.Version())) branch, err := update.NextSyncCommitteeBranchElectra()
if err != nil {
return false, err
}
return !reflect.DeepEqual(branch, interfaces.LightClientSyncCommitteeBranchElectra{}), nil
} }
branch, err := update.NextSyncCommitteeBranch()
payload, err := block.Block().Body().Execution()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get execution payload") return false, err
} }
return !reflect.DeepEqual(branch, interfaces.LightClientSyncCommitteeBranch{}), nil
transactionsRoot, err := ComputeTransactionsRoot(payload) }
if err != nil {
return nil, err func HasFinality(update interfaces.LightClientUpdate) (bool, error) {
} if update.Version() >= version.Electra {
withdrawalsRoot, err := ComputeWithdrawalsRoot(payload) b, err := update.FinalityBranchElectra()
if err != nil { if err != nil {
return nil, err return false, err
} }
blobGasUsed, err := payload.BlobGasUsed() return !reflect.DeepEqual(b, interfaces.LightClientFinalityBranchElectra{}), nil
if err != nil { }
return nil, errors.Wrap(err, "could not get blob gas used")
} b, err := update.FinalityBranch()
excessBlobGas, err := payload.ExcessBlobGas() if err != nil {
if err != nil { return false, err
return nil, errors.Wrap(err, "could not get excess blob gas") }
} return !reflect.DeepEqual(b, interfaces.LightClientFinalityBranch{}), nil
}
executionHeader := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(), func IsBetterUpdate(newUpdate, oldUpdate interfaces.LightClientUpdate) (bool, error) {
FeeRecipient: payload.FeeRecipient(), maxActiveParticipants := newUpdate.SyncAggregate().SyncCommitteeBits.Len()
StateRoot: payload.StateRoot(), newNumActiveParticipants := newUpdate.SyncAggregate().SyncCommitteeBits.Count()
ReceiptsRoot: payload.ReceiptsRoot(), oldNumActiveParticipants := oldUpdate.SyncAggregate().SyncCommitteeBits.Count()
LogsBloom: payload.LogsBloom(), newHasSupermajority := newNumActiveParticipants*3 >= maxActiveParticipants*2
PrevRandao: payload.PrevRandao(), oldHasSupermajority := oldNumActiveParticipants*3 >= maxActiveParticipants*2
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(), if newHasSupermajority != oldHasSupermajority {
GasUsed: payload.GasUsed(), return newHasSupermajority, nil
Timestamp: payload.Timestamp(), }
ExtraData: payload.ExtraData(), if !newHasSupermajority && newNumActiveParticipants != oldNumActiveParticipants {
BaseFeePerGas: payload.BaseFeePerGas(), return newNumActiveParticipants > oldNumActiveParticipants, nil
BlockHash: payload.BlockHash(), }
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot, newUpdateAttestedHeaderBeacon := newUpdate.AttestedHeader().Beacon()
BlobGasUsed: blobGasUsed, oldUpdateAttestedHeaderBeacon := oldUpdate.AttestedHeader().Beacon()
ExcessBlobGas: excessBlobGas,
} // Compare presence of relevant sync committee
newHasRelevantSyncCommittee, err := HasRelevantSyncCommittee(newUpdate)
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block()) if err != nil {
if err != nil { return false, err
return nil, errors.Wrap(err, "could not get execution payload proof") }
} newHasRelevantSyncCommittee = newHasRelevantSyncCommittee &&
(slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(newUpdate.SignatureSlot())))
parentRoot := block.Block().ParentRoot() oldHasRelevantSyncCommittee, err := HasRelevantSyncCommittee(oldUpdate)
stateRoot := block.Block().StateRoot() if err != nil {
bodyRoot, err := block.Block().Body().HashTreeRoot() return false, err
if err != nil { }
return nil, errors.Wrap(err, "could not get body root") oldHasRelevantSyncCommittee = oldHasRelevantSyncCommittee &&
} (slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdate.SignatureSlot())))
return &ethpbv2.LightClientHeaderDeneb{ if newHasRelevantSyncCommittee != oldHasRelevantSyncCommittee {
Beacon: &ethpbv1.BeaconBlockHeader{ return newHasRelevantSyncCommittee, nil
Slot: block.Block().Slot(), }
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:], // Compare indication of any finality
StateRoot: stateRoot[:], newHasFinality, err := HasFinality(newUpdate)
BodyRoot: bodyRoot[:], if err != nil {
}, return false, err
Execution: executionHeader, }
ExecutionBranch: executionPayloadProof, oldHasFinality, err := HasFinality(oldUpdate)
}, nil if err != nil {
return false, err
}
if newHasFinality != oldHasFinality {
return newHasFinality, nil
}
newUpdateFinalizedHeaderBeacon := newUpdate.FinalizedHeader().Beacon()
oldUpdateFinalizedHeaderBeacon := oldUpdate.FinalizedHeader().Beacon()
// Compare sync committee finality
if newHasFinality {
newHasSyncCommitteeFinality :=
slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateFinalizedHeaderBeacon.Slot)) ==
slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot))
oldHasSyncCommitteeFinality :=
slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateFinalizedHeaderBeacon.Slot)) ==
slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot))
if newHasSyncCommitteeFinality != oldHasSyncCommitteeFinality {
return newHasSyncCommitteeFinality, nil
}
}
// Tiebreaker 1: Sync committee participation beyond supermajority
if newNumActiveParticipants != oldNumActiveParticipants {
return newNumActiveParticipants > oldNumActiveParticipants, nil
}
// Tiebreaker 2: Prefer older data (fewer changes to best)
if newUpdateAttestedHeaderBeacon.Slot != oldUpdateAttestedHeaderBeacon.Slot {
return newUpdateAttestedHeaderBeacon.Slot < oldUpdateAttestedHeaderBeacon.Slot, nil
}
return newUpdate.SignatureSlot() < oldUpdate.SignatureSlot(), nil
}
func NewLightClientBootstrapFromBeaconState(
ctx context.Context,
currentSlot primitives.Slot,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
) (interfaces.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().AltairForkEpoch {
return nil, fmt.Errorf("light client bootstrap is not supported before Altair, invalid slot %d", state.Slot())
}
// assert state.slot == state.latest_block_header.slot
latestBlockHeader := state.LatestBlockHeader()
if state.Slot() != latestBlockHeader.Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
latestBlockHeader.StateRoot = stateRoot[:]
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
bootstrap, err := createDefaultLightClientBootstrap(currentSlot)
if err != nil {
return nil, errors.Wrap(err, "could not create default light client bootstrap")
}
lightClientHeader, err := BlockToLightClientHeader(ctx, currentSlot, block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
err = bootstrap.SetHeader(lightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not set header")
}
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
err = bootstrap.SetCurrentSyncCommittee(currentSyncCommittee)
if err != nil {
return nil, errors.Wrap(err, "could not set current sync committee")
}
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
err = bootstrap.SetCurrentSyncCommitteeBranch(currentSyncCommitteeProof)
if err != nil {
return nil, errors.Wrap(err, "could not set current sync committee proof")
}
return bootstrap, nil
}
func createDefaultLightClientBootstrap(currentSlot primitives.Slot) (interfaces.LightClientBootstrap, error) {
currentEpoch := slots.ToEpoch(currentSlot)
syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize
pubKeys := make([][]byte, syncCommitteeSize)
for i := uint64(0); i < syncCommitteeSize; i++ {
pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength)
}
currentSyncCommittee := &pb.SyncCommittee{
Pubkeys: pubKeys,
AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength),
}
var currentSyncCommitteeBranch [][]byte
if currentEpoch >= params.BeaconConfig().ElectraForkEpoch {
currentSyncCommitteeBranch = make([][]byte, fieldparams.SyncCommitteeBranchDepthElectra)
} else {
currentSyncCommitteeBranch = make([][]byte, fieldparams.SyncCommitteeBranchDepth)
}
for i := 0; i < len(currentSyncCommitteeBranch); i++ {
currentSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength)
}
executionBranch := make([][]byte, fieldparams.ExecutionBranchDepth)
for i := 0; i < fieldparams.ExecutionBranchDepth; i++ {
executionBranch[i] = make([]byte, 32)
}
// TODO: can this be based on the current epoch?
var m proto.Message
if currentEpoch < params.BeaconConfig().CapellaForkEpoch {
m = &pb.LightClientBootstrapAltair{
Header: &pb.LightClientHeaderAltair{
Beacon: &pb.BeaconBlockHeader{},
},
CurrentSyncCommittee: currentSyncCommittee,
CurrentSyncCommitteeBranch: currentSyncCommitteeBranch,
}
} else if currentEpoch < params.BeaconConfig().DenebForkEpoch {
m = &pb.LightClientBootstrapCapella{
Header: &pb.LightClientHeaderCapella{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderCapella{},
ExecutionBranch: executionBranch,
},
CurrentSyncCommittee: currentSyncCommittee,
CurrentSyncCommitteeBranch: currentSyncCommitteeBranch,
}
} else if currentEpoch < params.BeaconConfig().ElectraForkEpoch {
m = &pb.LightClientBootstrapDeneb{
Header: &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderDeneb{},
ExecutionBranch: executionBranch,
},
CurrentSyncCommittee: currentSyncCommittee,
CurrentSyncCommitteeBranch: currentSyncCommitteeBranch,
}
} else {
m = &pb.LightClientBootstrapElectra{
Header: &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{},
Execution: &enginev1.ExecutionPayloadHeaderDeneb{},
ExecutionBranch: executionBranch,
},
CurrentSyncCommittee: currentSyncCommittee,
CurrentSyncCommitteeBranch: currentSyncCommitteeBranch,
}
}
return light_client.NewWrappedBootstrap(m)
} }

View File

@@ -1,16 +1,17 @@
package light_client_test package light_client_test
import ( import (
"reflect"
"testing" "testing"
"github.com/pkg/errors" "github.com/pkg/errors"
lightClient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types" consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz" "github.com/prysmaticlabs/prysm/v5/encoding/ssz"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
lightClient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
"github.com/prysmaticlabs/prysm/v5/testing/require" "github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util" "github.com/prysmaticlabs/prysm/v5/testing/util"
) )
@@ -19,39 +20,39 @@ func TestLightClient_NewLightClientOptimisticUpdateFromBeaconState(t *testing.T)
t.Run("Altair", func(t *testing.T) { t.Run("Altair", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair() l := util.NewTestLightClient(t).SetupTestAltair()
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock) update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
}) })
t.Run("Capella", func(t *testing.T) { t.Run("Capella", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false) l := util.NewTestLightClient(t).SetupTestCapella(false)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock) update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
}) })
t.Run("Deneb", func(t *testing.T) { t.Run("Deneb", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(false) l := util.NewTestLightClient(t).SetupTestDeneb(false)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock) update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
}) })
} }
@@ -60,33 +61,33 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair() l := util.NewTestLightClient(t).SetupTestAltair()
t.Run("FinalizedBlock Not Nil", func(t *testing.T) { t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock) update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
finalizedBlockHeader, err := l.FinalizedBlock.Header() finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err) require.NoError(t, err)
//zeroHash := params.BeaconConfig().ZeroHash[:] //zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil") require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon() require.Equal(t, reflect.TypeOf(update.FinalizedHeader().Proto()), reflect.TypeOf(&pb.LightClientHeaderAltair{}), "Finalized header is not Altair")
require.NoError(t, err) updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal") require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal") require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves") fb, err := update.FinalityBranch()
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err) require.NoError(t, err)
for i, leaf := range update.FinalityBranch { proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal") require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
} }
}) })
}) })
@@ -95,30 +96,31 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
t.Run("FinalizedBlock Not Nil", func(t *testing.T) { t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false) l := util.NewTestLightClient(t).SetupTestCapella(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock) update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
finalizedBlockHeader, err := l.FinalizedBlock.Header() finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil") require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon() require.Equal(t, reflect.TypeOf(update.FinalizedHeader().Proto()), reflect.TypeOf(&pb.LightClientHeaderCapella{}), "Finalized header is not Capella")
require.NoError(t, err) updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal") require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal") require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves") fb, err := update.FinalityBranch()
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err) require.NoError(t, err)
for i, leaf := range update.FinalityBranch { proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal") require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
} }
// Check Execution BlockHash // Check Execution BlockHash
@@ -161,35 +163,38 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
TransactionsRoot: transactionsRoot, TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot, WithdrawalsRoot: withdrawalsRoot,
} }
require.DeepSSZEqual(t, execution, update.FinalizedHeader.GetHeaderCapella().Execution, "Finalized Block Execution is not equal") updateExecution, err := update.FinalizedHeader().Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, execution, updateExecution.Proto(), "Finalized Block Execution is not equal")
}) })
t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) { t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapellaFinalizedBlockAltair(false) l := util.NewTestLightClient(t).SetupTestCapellaFinalizedBlockAltair(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock) update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
finalizedBlockHeader, err := l.FinalizedBlock.Header() finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil") require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon() require.Equal(t, reflect.TypeOf(update.FinalizedHeader().Proto()), reflect.TypeOf(&pb.LightClientHeaderCapella{}), "Finalized header is not Capella")
require.NoError(t, err) updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal") require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal") require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves") fb, err := update.FinalityBranch()
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err) require.NoError(t, err)
for i, leaf := range update.FinalityBranch { proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal") require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
} }
}) })
}) })
@@ -199,31 +204,31 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
t.Run("FinalizedBlock Not Nil", func(t *testing.T) { t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(false) l := util.NewTestLightClient(t).SetupTestDeneb(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock) update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
//zeroHash := params.BeaconConfig().ZeroHash[:] //zeroHash := params.BeaconConfig().ZeroHash[:]
finalizedBlockHeader, err := l.FinalizedBlock.Header() finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil") require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon() updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.NoError(t, err)
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal") require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal") require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves") fb, err := update.FinalityBranch()
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err) require.NoError(t, err)
for i, leaf := range update.FinalityBranch { proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal") require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
} }
// Check Execution BlockHash // Check Execution BlockHash
@@ -266,36 +271,39 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
TransactionsRoot: transactionsRoot, TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot, WithdrawalsRoot: withdrawalsRoot,
} }
require.DeepSSZEqual(t, execution, update.FinalizedHeader.GetHeaderDeneb().Execution, "Finalized Block Execution is not equal") updateExecution, err := update.FinalizedHeader().Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, execution, updateExecution.Proto(), "Finalized Block Execution is not equal")
}) })
t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) { t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDenebFinalizedBlockCapella(false) l := util.NewTestLightClient(t).SetupTestDenebFinalizedBlockCapella(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock) update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State.Slot(), l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update, "update is nil") require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal") require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate) l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader) l.CheckAttestedHeader(update.AttestedHeader())
finalizedBlockHeader, err := l.FinalizedBlock.Header() finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil") require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon() updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.NoError(t, err) require.Equal(t, reflect.TypeOf(update.FinalizedHeader().Proto()), reflect.TypeOf(&pb.LightClientHeaderDeneb{}), "Finalized header is not Deneb")
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal") require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal") require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal") require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves") fb, err := update.FinalityBranch()
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err) require.NoError(t, err)
for i, leaf := range update.FinalityBranch { proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal") require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
} }
// Check Execution BlockHash // Check Execution BlockHash
@@ -321,7 +329,7 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
} else { } else {
require.NoError(t, err) require.NoError(t, err)
} }
execution := &v11.ExecutionPayloadHeaderCapella{ execution := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payloadInterface.ParentHash(), ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(), FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(), StateRoot: payloadInterface.StateRoot(),
@@ -338,7 +346,9 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
TransactionsRoot: transactionsRoot, TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot, WithdrawalsRoot: withdrawalsRoot,
} }
require.DeepSSZEqual(t, execution, update.FinalizedHeader.GetHeaderCapella().Execution, "Finalized Block Execution is not equal") updateExecution, err := update.FinalizedHeader().Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, execution, updateExecution.Proto(), "Finalized Block Execution is not equal")
}) })
}) })
} }
@@ -347,9 +357,8 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
t.Run("Altair", func(t *testing.T) { t.Run("Altair", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair() l := util.NewTestLightClient(t).SetupTestAltair()
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderAltair()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -357,19 +366,18 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
bodyRoot, err := l.Block.Block().Body().HashTreeRoot() bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
}) })
t.Run("Bellatrix", func(t *testing.T) { t.Run("Bellatrix", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestBellatrix() l := util.NewTestLightClient(t).SetupTestBellatrix()
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderAltair()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -377,20 +385,19 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
bodyRoot, err := l.Block.Block().Body().HashTreeRoot() bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
}) })
t.Run("Capella", func(t *testing.T) { t.Run("Capella", func(t *testing.T) {
t.Run("Non-Blinded Beacon Block", func(t *testing.T) { t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false) l := util.NewTestLightClient(t).SetupTestCapella(false)
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderCapella()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -428,23 +435,26 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal") headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal") headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
}) })
t.Run("Blinded Beacon Block", func(t *testing.T) { t.Run("Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(true) l := util.NewTestLightClient(t).SetupTestCapella(true)
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderCapella()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -482,15 +492,19 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal") headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal") headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
}) })
}) })
@@ -498,9 +512,8 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
t.Run("Non-Blinded Beacon Block", func(t *testing.T) { t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(false) l := util.NewTestLightClient(t).SetupTestDeneb(false)
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderDeneb()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -546,23 +559,26 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal") headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal") headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
}) })
t.Run("Blinded Beacon Block", func(t *testing.T) { t.Run("Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(true) l := util.NewTestLightClient(t).SetupTestDeneb(true)
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderDeneb()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -608,15 +624,19 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal") headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal") headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
}) })
}) })
@@ -624,9 +644,8 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
t.Run("Non-Blinded Beacon Block", func(t *testing.T) { t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestElectra(false) l := util.NewTestLightClient(t).SetupTestElectra(false)
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderDeneb()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -672,23 +691,26 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal") headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal") headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
}) })
t.Run("Blinded Beacon Block", func(t *testing.T) { t.Run("Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestElectra(true) l := util.NewTestLightClient(t).SetupTestElectra(true)
container, err := lightClient.BlockToLightClientHeader(l.Block) header, err := lightClient.BlockToLightClientHeader(l.Ctx, l.State.Slot(), l.Block)
require.NoError(t, err) require.NoError(t, err)
header := container.GetHeaderDeneb()
require.NotNil(t, header, "header is nil") require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot() parentRoot := l.Block.Block().ParentRoot()
@@ -734,15 +756,27 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal") require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal") require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal") require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal") require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal") require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal") headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal") headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
}) })
}) })
} }
func convertArrayToSlice(arr [4][32]uint8) [][]uint8 {
slice := make([][]uint8, len(arr))
for i := range arr {
slice[i] = arr[i][:]
}
return slice
}

View File

@@ -18,7 +18,6 @@ go_library(
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
"//monitoring/backup:go_default_library", "//monitoring/backup:go_default_library",
"//proto/dbval:go_default_library", "//proto/dbval:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library",
], ],

View File

@@ -7,8 +7,6 @@ import (
"context" "context"
"io" "io"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters" "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters"
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types" slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
@@ -59,8 +57,9 @@ type ReadOnlyDatabase interface {
FeeRecipientByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (common.Address, error) FeeRecipientByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (common.Address, error)
RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error)
// light client operations // light client operations
LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]*ethpbv2.LightClientUpdateWithVersion, error) LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]interfaces.LightClientUpdate, error)
LightClientUpdate(ctx context.Context, period uint64) (*ethpbv2.LightClientUpdateWithVersion, error) LightClientUpdate(ctx context.Context, period uint64) (interfaces.LightClientUpdate, error)
LightClientBootstrap(ctx context.Context, blockRoot []byte) (interfaces.LightClientBootstrap, error)
// origin checkpoint sync support // origin checkpoint sync support
OriginCheckpointBlockRoot(ctx context.Context) ([32]byte, error) OriginCheckpointBlockRoot(ctx context.Context) ([32]byte, error)
@@ -98,7 +97,8 @@ type NoHeadAccessDatabase interface {
SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []primitives.ValidatorIndex, addrs []common.Address) error SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []primitives.ValidatorIndex, addrs []common.Address) error
SaveRegistrationsByValidatorIDs(ctx context.Context, ids []primitives.ValidatorIndex, regs []*ethpb.ValidatorRegistrationV1) error SaveRegistrationsByValidatorIDs(ctx context.Context, ids []primitives.ValidatorIndex, regs []*ethpb.ValidatorRegistrationV1) error
// light client operations // light client operations
SaveLightClientUpdate(ctx context.Context, period uint64, update *ethpbv2.LightClientUpdateWithVersion) error SaveLightClientUpdate(ctx context.Context, period uint64, update interfaces.LightClientUpdate) error
SaveLightClientBootstrap(ctx context.Context, blockRoot []byte, bootstrap interfaces.LightClientBootstrap) error
CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint primitives.Slot) error CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint primitives.Slot) error
} }

View File

@@ -44,6 +44,7 @@ go_library(
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types/blocks:go_default_library", "//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library", "//consensus-types/interfaces:go_default_library",
"//consensus-types/light-client:go_default_library",
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
"//container/slice:go_default_library", "//container/slice:go_default_library",
"//encoding/bytesutil:go_default_library", "//encoding/bytesutil:go_default_library",
@@ -53,7 +54,6 @@ go_library(
"//monitoring/tracing:go_default_library", "//monitoring/tracing:go_default_library",
"//monitoring/tracing/trace:go_default_library", "//monitoring/tracing/trace:go_default_library",
"//proto/dbval:go_default_library", "//proto/dbval:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library", "//runtime/version:go_default_library",
"//time:go_default_library", "//time:go_default_library",
@@ -112,18 +112,18 @@ go_test(
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types/blocks:go_default_library", "//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library", "//consensus-types/interfaces:go_default_library",
"//consensus-types/light-client:go_default_library",
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library", "//encoding/bytesutil:go_default_library",
"//proto/dbval:go_default_library", "//proto/dbval:go_default_library",
"//proto/engine/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//proto/testing:go_default_library", "//proto/testing:go_default_library",
"//runtime/version:go_default_library", "//runtime/version:go_default_library",
"//testing/assert:go_default_library", "//testing/assert:go_default_library",
"//testing/require:go_default_library", "//testing/require:go_default_library",
"//testing/util:go_default_library", "//testing/util:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_golang_snappy//:go_default_library", "@com_github_golang_snappy//:go_default_library",
"@com_github_pkg_errors//:go_default_library", "@com_github_pkg_errors//:go_default_library",

View File

@@ -108,6 +108,7 @@ var Buckets = [][]byte{
stateSummaryBucket, stateSummaryBucket,
stateValidatorsBucket, stateValidatorsBucket,
lightClientUpdatesBucket, lightClientUpdatesBucket,
lightClientBootstrapBucket,
// Indices buckets. // Indices buckets.
blockSlotIndicesBucket, blockSlotIndicesBucket,
stateSlotIndicesBucket, stateSlotIndicesBucket,

View File

@@ -5,35 +5,126 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/golang/snappy"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
light_client "github.com/prysmaticlabs/prysm/v5/consensus-types/light-client"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
"google.golang.org/protobuf/proto"
) )
func (s *Store) SaveLightClientUpdate(ctx context.Context, period uint64, update *ethpbv2.LightClientUpdateWithVersion) error { func (s *Store) SaveLightClientUpdate(ctx context.Context, period uint64, update interfaces.LightClientUpdate) error {
ctx, span := trace.StartSpan(ctx, "BeaconDB.saveLightClientUpdate") _, span := trace.StartSpan(ctx, "BeaconDB.SaveLightClientUpdate")
defer span.End() defer span.End()
return s.db.Update(func(tx *bolt.Tx) error { return s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(lightClientUpdatesBucket) bkt := tx.Bucket(lightClientUpdatesBucket)
updateMarshalled, err := encode(ctx, update) enc, err := encodeLightClientUpdate(update)
if err != nil { if err != nil {
return err return err
} }
return bkt.Put(bytesutil.Uint64ToBytesBigEndian(period), updateMarshalled) return bkt.Put(bytesutil.Uint64ToBytesBigEndian(period), enc)
}) })
} }
func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]*ethpbv2.LightClientUpdateWithVersion, error) { func (s *Store) SaveLightClientBootstrap(ctx context.Context, blockRoot []byte, bootstrap interfaces.LightClientBootstrap) error {
ctx, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdates") _, span := trace.StartSpan(ctx, "BeaconDB.SaveLightClientBootstrap")
defer span.End()
return s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(lightClientBootstrapBucket)
enc, err := encodeLightClientBootstrap(bootstrap)
if err != nil {
return err
}
return bkt.Put(blockRoot, enc)
})
}
func (s *Store) LightClientBootstrap(ctx context.Context, blockRoot []byte) (interfaces.LightClientBootstrap, error) {
_, span := trace.StartSpan(ctx, "BeaconDB.LightClientBootstrap")
defer span.End()
var bootstrap interfaces.LightClientBootstrap
err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(lightClientBootstrapBucket)
enc := bkt.Get(blockRoot)
if enc == nil {
return nil
}
var err error
bootstrap, err = decodeLightClientBootstrap(enc)
return err
})
return bootstrap, err
}
func encodeLightClientBootstrap(bootstrap interfaces.LightClientBootstrap) ([]byte, error) {
key, err := keyForLightClientUpdate(bootstrap.Version())
if err != nil {
return nil, err
}
enc, err := bootstrap.MarshalSSZ()
if err != nil {
return nil, errors.Wrap(err, "could not marshal light client bootstrap")
}
fullEnc := make([]byte, len(key)+len(enc))
copy(fullEnc, key)
copy(fullEnc[len(key):], enc)
return snappy.Encode(nil, fullEnc), nil
}
func decodeLightClientBootstrap(enc []byte) (interfaces.LightClientBootstrap, error) {
var err error
enc, err = snappy.Decode(nil, enc)
if err != nil {
return nil, errors.Wrap(err, "could not snappy decode light client bootstrap")
}
var m proto.Message
switch {
case hasAltairKey(enc):
bootstrap := &ethpb.LightClientBootstrapAltair{}
if err := bootstrap.UnmarshalSSZ(enc[len(altairKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Altair light client bootstrap")
}
m = bootstrap
case hasCapellaKey(enc):
bootstrap := &ethpb.LightClientBootstrapCapella{}
if err := bootstrap.UnmarshalSSZ(enc[len(capellaKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Capella light client bootstrap")
}
m = bootstrap
case hasDenebKey(enc):
bootstrap := &ethpb.LightClientBootstrapDeneb{}
if err := bootstrap.UnmarshalSSZ(enc[len(denebKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Deneb light client bootstrap")
}
m = bootstrap
case hasElectraKey(enc):
bootstrap := &ethpb.LightClientBootstrapElectra{}
if err := bootstrap.UnmarshalSSZ(enc[len(electraKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Electra light client bootstrap")
}
m = bootstrap
default:
return nil, errors.New("decoding of saved light client bootstrap is unsupported")
}
return light_client.NewWrappedBootstrap(m)
}
func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]interfaces.LightClientUpdate, error) {
_, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdates")
defer span.End() defer span.End()
if startPeriod > endPeriod { if startPeriod > endPeriod {
return nil, fmt.Errorf("start period %d is greater than end period %d", startPeriod, endPeriod) return nil, fmt.Errorf("start period %d is greater than end period %d", startPeriod, endPeriod)
} }
updates := make(map[uint64]*ethpbv2.LightClientUpdateWithVersion) updates := make(map[uint64]interfaces.LightClientUpdate)
err := s.db.View(func(tx *bolt.Tx) error { err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(lightClientUpdatesBucket) bkt := tx.Bucket(lightClientUpdatesBucket)
c := bkt.Cursor() c := bkt.Cursor()
@@ -46,11 +137,11 @@ func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod u
for k, v := c.Seek(bytesutil.Uint64ToBytesBigEndian(startPeriod)); k != nil && binary.BigEndian.Uint64(k) <= endPeriod; k, v = c.Next() { for k, v := c.Seek(bytesutil.Uint64ToBytesBigEndian(startPeriod)); k != nil && binary.BigEndian.Uint64(k) <= endPeriod; k, v = c.Next() {
currentPeriod := binary.BigEndian.Uint64(k) currentPeriod := binary.BigEndian.Uint64(k)
var update ethpbv2.LightClientUpdateWithVersion update, err := decodeLightClientUpdate(v)
if err := decode(ctx, v, &update); err != nil { if err != nil {
return err return err
} }
updates[currentPeriod] = &update updates[currentPeriod] = update
} }
return nil return nil
@@ -62,18 +153,88 @@ func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod u
return updates, err return updates, err
} }
func (s *Store) LightClientUpdate(ctx context.Context, period uint64) (*ethpbv2.LightClientUpdateWithVersion, error) { func (s *Store) LightClientUpdate(ctx context.Context, period uint64) (interfaces.LightClientUpdate, error) {
ctx, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdate") _, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdate")
defer span.End() defer span.End()
var update ethpbv2.LightClientUpdateWithVersion var update interfaces.LightClientUpdate
err := s.db.View(func(tx *bolt.Tx) error { err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(lightClientUpdatesBucket) bkt := tx.Bucket(lightClientUpdatesBucket)
updateBytes := bkt.Get(bytesutil.Uint64ToBytesBigEndian(period)) updateBytes := bkt.Get(bytesutil.Uint64ToBytesBigEndian(period))
if updateBytes == nil { if updateBytes == nil {
return nil return nil
} }
return decode(ctx, updateBytes, &update) var err error
update, err = decodeLightClientUpdate(updateBytes)
return err
}) })
return &update, err return update, err
}
func encodeLightClientUpdate(update interfaces.LightClientUpdate) ([]byte, error) {
key, err := keyForLightClientUpdate(update.Version())
if err != nil {
return nil, err
}
enc, err := update.MarshalSSZ()
if err != nil {
return nil, errors.Wrap(err, "could not marshal light client update")
}
fullEnc := make([]byte, len(key)+len(enc))
copy(fullEnc, key)
copy(fullEnc[len(key):], enc)
return snappy.Encode(nil, fullEnc), nil
}
func decodeLightClientUpdate(enc []byte) (interfaces.LightClientUpdate, error) {
var err error
enc, err = snappy.Decode(nil, enc)
if err != nil {
return nil, errors.Wrap(err, "could not snappy decode light client update")
}
var m proto.Message
switch {
case hasAltairKey(enc):
update := &ethpb.LightClientUpdateAltair{}
if err := update.UnmarshalSSZ(enc[len(altairKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Altair light client update")
}
m = update
case hasCapellaKey(enc):
update := &ethpb.LightClientUpdateCapella{}
if err := update.UnmarshalSSZ(enc[len(capellaKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Capella light client update")
}
m = update
case hasDenebKey(enc):
update := &ethpb.LightClientUpdateDeneb{}
if err := update.UnmarshalSSZ(enc[len(denebKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Deneb light client update")
}
m = update
case hasElectraKey(enc):
update := &ethpb.LightClientUpdateElectra{}
if err := update.UnmarshalSSZ(enc[len(electraKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Electra light client update")
}
m = update
default:
return nil, errors.New("decoding of saved light client update is unsupported")
}
return light_client.NewWrappedUpdate(m)
}
func keyForLightClientUpdate(v int) ([]byte, error) {
switch v {
case version.Electra:
return electraKey, nil
case version.Deneb:
return denebKey, nil
case version.Capella:
return capellaKey, nil
case version.Altair:
return altairKey, nil
default:
return nil, fmt.Errorf("unsupported light client update version %s", version.String(v))
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,8 @@ var (
registrationBucket = []byte("registration") registrationBucket = []byte("registration")
// Light Client Updates Bucket // Light Client Updates Bucket
lightClientUpdatesBucket = []byte("light-client-updates") lightClientUpdatesBucket = []byte("light-client-updates")
lightClientBootstrapBucket = []byte("light-client-bootstrap")
// Deprecated: This bucket was migrated in PR 6461. Do not use, except for migrations. // Deprecated: This bucket was migrated in PR 6461. Do not use, except for migrations.
slotsHasObjectBucket = []byte("slots-has-objects") slotsHasObjectBucket = []byte("slots-has-objects")

View File

@@ -801,7 +801,7 @@ func tDStringToUint256(td string) (*uint256.Int, error) {
return i, nil return i, nil
} }
func buildEmptyExecutionPayload(v int) (proto.Message, error) { func EmptyExecutionPayload(v int) (proto.Message, error) {
switch v { switch v {
case version.Bellatrix: case version.Bellatrix:
return &pb.ExecutionPayload{ return &pb.ExecutionPayload{

View File

@@ -205,7 +205,7 @@ func (r *blindedBlockReconstructor) requestBodiesByHash(ctx context.Context, cli
func (r *blindedBlockReconstructor) payloadForHeader(header interfaces.ExecutionData, v int) (proto.Message, error) { func (r *blindedBlockReconstructor) payloadForHeader(header interfaces.ExecutionData, v int) (proto.Message, error) {
bodyKey := bytesutil.ToBytes32(header.BlockHash()) bodyKey := bytesutil.ToBytes32(header.BlockHash())
if bodyKey == params.BeaconConfig().ZeroHash { if bodyKey == params.BeaconConfig().ZeroHash {
payload, err := buildEmptyExecutionPayload(v) payload, err := EmptyExecutionPayload(v)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to reconstruct payload for body hash %#x", bodyKey) return nil, errors.Wrapf(err, "failed to reconstruct payload for body hash %#x", bodyKey)
} }

View File

@@ -918,10 +918,11 @@ func (*Service) configEndpoints() []endpoint {
func (s *Service) lightClientEndpoints(blocker lookup.Blocker, stater lookup.Stater) []endpoint { func (s *Service) lightClientEndpoints(blocker lookup.Blocker, stater lookup.Stater) []endpoint {
server := &lightclient.Server{ server := &lightclient.Server{
Blocker: blocker, Blocker: blocker,
Stater: stater, Stater: stater,
HeadFetcher: s.cfg.HeadFetcher, HeadFetcher: s.cfg.HeadFetcher,
BeaconDB: s.cfg.BeaconDB, ChainInfoFetcher: s.cfg.ChainInfoFetcher,
BeaconDB: s.cfg.BeaconDB,
} }
const namespace = "lightclient" const namespace = "lightclient"

View File

@@ -20,13 +20,13 @@ go_library(
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library", "//beacon-chain/core/time:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library", "//consensus-types/payload-attribute:go_default_library",
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
"//monitoring/tracing/trace:go_default_library", "//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library", "//network/httputil:go_default_library",
"//proto/engine/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library", "//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library", "//runtime/version:go_default_library",
"//time/slots:go_default_library", "//time/slots:go_default_library",

View File

@@ -22,13 +22,13 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
chaintime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" chaintime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v5/consensus-types/payload-attribute" payloadattribute "github.com/prysmaticlabs/prysm/v5/consensus-types/payload-attribute"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/network/httputil" "github.com/prysmaticlabs/prysm/v5/network/httputil"
engine "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" engine "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots" "github.com/prysmaticlabs/prysm/v5/time/slots"
@@ -431,9 +431,9 @@ func topicForEvent(event *feed.Event) string {
return HeadTopic return HeadTopic
case *ethpb.EventFinalizedCheckpoint: case *ethpb.EventFinalizedCheckpoint:
return FinalizedCheckpointTopic return FinalizedCheckpointTopic
case *ethpbv2.LightClientFinalityUpdateWithVersion: case interfaces.LightClientFinalityUpdate:
return LightClientFinalityUpdateTopic return LightClientFinalityUpdateTopic
case *ethpbv2.LightClientOptimisticUpdateWithVersion: case interfaces.LightClientOptimisticUpdate:
return LightClientOptimisticUpdateTopic return LightClientOptimisticUpdateTopic
case *ethpb.EventChainReorg: case *ethpb.EventChainReorg:
return ChainReorgTopic return ChainReorgTopic
@@ -527,25 +527,25 @@ func (s *Server) lazyReaderForEvent(ctx context.Context, event *feed.Event, topi
return func() io.Reader { return func() io.Reader {
return jsonMarshalReader(eventName, structs.FinalizedCheckpointEventFromV1(v)) return jsonMarshalReader(eventName, structs.FinalizedCheckpointEventFromV1(v))
}, nil }, nil
case *ethpbv2.LightClientFinalityUpdateWithVersion: case interfaces.LightClientFinalityUpdate:
cv, err := structs.LightClientFinalityUpdateFromConsensus(v.Data) cv, err := structs.LightClientFinalityUpdateFromConsensus(v)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "LightClientFinalityUpdateWithVersion event conversion failure") return nil, errors.Wrap(err, "LightClientFinalityUpdate conversion failure")
} }
ev := &structs.LightClientFinalityUpdateEvent{ ev := &structs.LightClientFinalityUpdateEvent{
Version: version.String(int(v.Version)), Version: version.String(v.Version()),
Data: cv, Data: cv,
} }
return func() io.Reader { return func() io.Reader {
return jsonMarshalReader(eventName, ev) return jsonMarshalReader(eventName, ev)
}, nil }, nil
case *ethpbv2.LightClientOptimisticUpdateWithVersion: case interfaces.LightClientOptimisticUpdate:
cv, err := structs.LightClientOptimisticUpdateFromConsensus(v.Data) cv, err := structs.LightClientOptimisticUpdateFromConsensus(v)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "LightClientOptimisticUpdateWithVersion event conversion failure") return nil, errors.Wrap(err, "LightClientOptimisticUpdate conversion failure")
} }
ev := &structs.LightClientOptimisticUpdateEvent{ ev := &structs.LightClientOptimisticUpdateEvent{
Version: version.String(int(v.Version)), Version: version.String(v.Version()),
Data: cv, Data: cv,
} }
return func() io.Reader { return func() io.Reader {

View File

@@ -18,16 +18,12 @@ go_library(
"//beacon-chain/rpc/eth/shared:go_default_library", "//beacon-chain/rpc/eth/shared:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library", "//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library", "//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
"//monitoring/tracing/trace:go_default_library", "//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library", "//network/httputil:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",
"//runtime/version:go_default_library", "//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library", "@com_github_pkg_errors//:go_default_library",
"@com_github_wealdtech_go_bytesutil//:go_default_library", "@com_github_wealdtech_go_bytesutil//:go_default_library",
@@ -46,16 +42,18 @@ go_test(
"//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/light-client: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/rpc/testutil:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library", "//config/fieldparams:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types/blocks:go_default_library", "//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library", "//consensus-types/interfaces:go_default_library",
"//consensus-types/light-client:go_default_library",
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
"//proto/eth/v1:go_default_library", "//proto/engine/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library", "//testing/assert:go_default_library",
"//testing/require:go_default_library", "//testing/require:go_default_library",
"//testing/util:go_default_library", "//testing/util:go_default_library",

View File

@@ -10,11 +10,10 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/api" "github.com/prysmaticlabs/prysm/v5/api"
"github.com/prysmaticlabs/prysm/v5/api/server/structs" "github.com/prysmaticlabs/prysm/v5/api/server/structs"
lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/network/httputil" "github.com/prysmaticlabs/prysm/v5/network/httputil"
"github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/runtime/version"
@@ -47,18 +46,32 @@ func (s *Server) GetLightClientBootstrap(w http.ResponseWriter, req *http.Reques
return return
} }
bootstrap, err := createLightClientBootstrap(ctx, state, blk) bootstrap, err := lightclient.NewLightClientBootstrapFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), state, blk)
if err != nil { if err != nil {
httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError) httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError)
return return
} }
response := &structs.LightClientBootstrapResponse{ w.Header().Set(api.VersionHeader, version.String(bootstrap.Version()))
Version: version.String(blk.Version()),
Data: bootstrap,
}
w.Header().Set(api.VersionHeader, version.String(version.Deneb))
httputil.WriteJson(w, response) if httputil.RespondWithSsz(req) {
ssz, err := bootstrap.MarshalSSZ()
if err != nil {
httputil.HandleError(w, "could not marshal bootstrap to SSZ: "+err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteSsz(w, ssz, "light_client_bootstrap.ssz")
} else {
data, err := structs.LightClientBootstrapFromConsensus(bootstrap)
if err != nil {
httputil.HandleError(w, "could not marshal bootstrap to JSON: "+err.Error(), http.StatusInternalServerError)
return
}
response := &structs.LightClientBootstrapResponse{
Version: version.String(bootstrap.Version()),
Data: data,
}
httputil.WriteJson(w, response)
}
} }
// GetLightClientUpdatesByRange - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/updates.yaml // GetLightClientUpdatesByRange - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/updates.yaml
@@ -117,110 +130,33 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
endPeriod = maxSlot / slotsPerPeriod endPeriod = maxSlot / slotsPerPeriod
} }
// Populate updates // get updates
var updates []*structs.LightClientUpdateResponse updatesMap, err := s.BeaconDB.LightClientUpdates(ctx, startPeriod, endPeriod)
for period := startPeriod; period <= endPeriod; period++ { if err != nil {
// Get the last known state of the period, httputil.HandleError(w, "Could not get light client updates from DB: "+err.Error(), http.StatusInternalServerError)
// 1. We wish the block has a parent in the same period if possible
// 2. We wish the block has a state in the same period
lastSlotInPeriod := period*slotsPerPeriod + slotsPerPeriod - 1
if lastSlotInPeriod > maxSlot {
lastSlotInPeriod = maxSlot
}
firstSlotInPeriod := period * slotsPerPeriod
// Let's not use the first slot in the period, otherwise the attested header will be in previous period
firstSlotInPeriod++
var state state.BeaconState
var block interfaces.ReadOnlySignedBeaconBlock
for slot := lastSlotInPeriod; slot >= firstSlotInPeriod; slot-- {
state, err = s.Stater.StateBySlot(ctx, types.Slot(slot))
if err != nil {
continue
}
// Get the block
latestBlockHeader := state.LatestBlockHeader()
latestStateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
continue
}
latestBlockHeader.StateRoot = latestStateRoot[:]
blockRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
continue
}
block, err = s.Blocker.Block(ctx, blockRoot[:])
if err != nil || block == nil {
continue
}
syncAggregate, err := block.Block().Body().SyncAggregate()
if err != nil || syncAggregate == nil {
continue
}
if syncAggregate.SyncCommitteeBits.Count()*3 < config.SyncCommitteeSize*2 {
// Not enough votes
continue
}
break
}
if block == nil {
// No valid block found for the period
continue
}
// Get attested state
attestedRoot := block.Block().ParentRoot()
attestedBlock, err := s.Blocker.Block(ctx, attestedRoot[:])
if err != nil || attestedBlock == nil {
continue
}
attestedSlot := attestedBlock.Block().Slot()
attestedState, err := s.Stater.StateBySlot(ctx, attestedSlot)
if err != nil {
continue
}
// Get finalized block
var finalizedBlock interfaces.ReadOnlySignedBeaconBlock
finalizedCheckPoint := attestedState.FinalizedCheckpoint()
if finalizedCheckPoint != nil {
finalizedRoot := bytesutil.ToBytes32(finalizedCheckPoint.Root)
finalizedBlock, err = s.Blocker.Block(ctx, finalizedRoot[:])
if err != nil {
finalizedBlock = nil
}
}
update, err := newLightClientUpdateFromBeaconState(
ctx,
state,
block,
attestedState,
attestedBlock,
finalizedBlock,
)
if err == nil {
updates = append(updates, &structs.LightClientUpdateResponse{
Version: version.String(attestedState.Version()),
Data: update,
})
}
}
if len(updates) == 0 {
httputil.HandleError(w, "no updates found", http.StatusNotFound)
return return
} }
updates := make([]*structs.LightClientUpdateResponse, 0, len(updatesMap))
for i := startPeriod; i <= endPeriod; i++ {
update, ok := updatesMap[i]
if !ok {
// Only return the first contiguous range of updates
break
}
updateJson, err := structs.LightClientUpdateFromConsensus(update)
if err != nil {
httputil.HandleError(w, "Could not convert light client update: "+err.Error(), http.StatusInternalServerError)
return
}
updateResponse := &structs.LightClientUpdateResponse{
Version: version.String(update.Version()),
Data: updateJson,
}
updates = append(updates, updateResponse)
}
httputil.WriteJson(w, updates) httputil.WriteJson(w, updates)
} }
@@ -268,7 +204,7 @@ func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.R
return return
} }
update, err := newLightClientFinalityUpdateFromBeaconState(ctx, st, block, attestedState, attestedBlock, finalizedBlock) update, err := newLightClientFinalityUpdateFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), st, block, attestedState, attestedBlock, finalizedBlock)
if err != nil { if err != nil {
httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError) httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError)
return return
@@ -313,7 +249,7 @@ func (s *Server) GetLightClientOptimisticUpdate(w http.ResponseWriter, req *http
return return
} }
update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, st, block, attestedState, attestedBlock) update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), st, block, attestedState, attestedBlock)
if err != nil { if err != nil {
httputil.HandleError(w, "Could not get light client optimistic update: "+err.Error(), http.StatusInternalServerError) httputil.HandleError(w, "Could not get light client optimistic update: "+err.Error(), http.StatusInternalServerError)
return return

File diff suppressed because it is too large Load Diff

View File

@@ -2,274 +2,25 @@ package lightclient
import ( import (
"context" "context"
"encoding/json"
"fmt"
"reflect"
"github.com/pkg/errors" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/proto/migration"
lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/prysm/v5/api/server/structs" "github.com/prysmaticlabs/prysm/v5/api/server/structs"
lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/time/slots"
) )
func createLightClientBootstrap(ctx context.Context, state state.BeaconState, blk interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
switch blk.Version() {
case version.Phase0:
return nil, fmt.Errorf("light client bootstrap is not supported for phase0")
case version.Altair, version.Bellatrix:
return createLightClientBootstrapAltair(ctx, state, blk)
case version.Capella:
return createLightClientBootstrapCapella(ctx, state, blk)
case version.Deneb, version.Electra:
return createLightClientBootstrapDeneb(ctx, state, blk)
}
return nil, fmt.Errorf("unsupported block version %s", version.String(blk.Version()))
}
func createLightClientBootstrapAltair(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().AltairForkEpoch {
return nil, fmt.Errorf("light client bootstrap is not supported before Altair, invalid slot %d", state.Slot())
}
// assert state.slot == state.latest_block_header.slot
latestBlockHeader := state.LatestBlockHeader()
if state.Slot() != latestBlockHeader.Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
latestBlockHeader.StateRoot = stateRoot[:]
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
lightClientHeader := lightClientHeaderContainer.GetHeaderAltair()
apiLightClientHeader := &structs.LightClientHeader{
Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)),
}
headerJSON, err := json.Marshal(apiLightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
branch := make([]string, fieldparams.SyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
result := &structs.LightClientBootstrap{
Header: headerJSON,
CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee),
CurrentSyncCommitteeBranch: branch,
}
return result, nil
}
func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= CAPELLA_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().CapellaForkEpoch {
return nil, fmt.Errorf("creating Capella light client bootstrap is not supported before Capella, invalid slot %d", state.Slot())
}
// assert state.slot == state.latest_block_header.slot
latestBlockHeader := state.LatestBlockHeader()
if state.Slot() != latestBlockHeader.Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
latestBlockHeader.StateRoot = stateRoot[:]
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
lightClientHeader := lightClientHeaderContainer.GetHeaderCapella()
apiLightClientHeader := &structs.LightClientHeader{
Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)),
}
headerJSON, err := json.Marshal(apiLightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
branch := make([]string, fieldparams.SyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
result := &structs.LightClientBootstrap{
Header: headerJSON,
CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee),
CurrentSyncCommitteeBranch: branch,
}
return result, nil
}
func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= DENEB_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().DenebForkEpoch {
return nil, fmt.Errorf("creating Deneb light client bootstrap is not supported before Deneb, invalid slot %d", state.Slot())
}
// assert state.slot == state.latest_block_header.slot
latestBlockHeader := state.LatestBlockHeader()
if state.Slot() != latestBlockHeader.Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
latestBlockHeader.StateRoot = stateRoot[:]
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
lightClientHeader := lightClientHeaderContainer.GetHeaderDeneb()
apiLightClientHeader := &structs.LightClientHeader{
Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)),
}
headerJSON, err := json.Marshal(apiLightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
var branch []string
switch block.Version() {
case version.Deneb:
branch = make([]string, fieldparams.SyncCommitteeBranchDepth)
case version.Electra:
branch = make([]string, fieldparams.SyncCommitteeBranchDepthElectra)
}
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
result := &structs.LightClientBootstrap{
Header: headerJSON,
CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee),
CurrentSyncCommitteeBranch: branch,
}
return result, nil
}
func newLightClientUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientUpdate, error) {
result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock)
if err != nil {
return nil, err
}
return structs.LightClientUpdateFromConsensus(result)
}
func newLightClientFinalityUpdateFromBeaconState( func newLightClientFinalityUpdateFromBeaconState(
ctx context.Context, ctx context.Context,
currentSlot primitives.Slot,
state state.BeaconState, state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock, block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState, attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock, attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock, finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientFinalityUpdate, error) { ) (*structs.LightClientFinalityUpdate, error) {
result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock) result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, finalizedBlock)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -279,94 +30,16 @@ func newLightClientFinalityUpdateFromBeaconState(
func newLightClientOptimisticUpdateFromBeaconState( func newLightClientOptimisticUpdateFromBeaconState(
ctx context.Context, ctx context.Context,
currentSlot primitives.Slot,
state state.BeaconState, state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock, block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState, attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock, attestedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientOptimisticUpdate, error) { ) (*structs.LightClientOptimisticUpdate, error) {
result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock) result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return structs.LightClientOptimisticUpdateFromConsensus(result) return structs.LightClientOptimisticUpdateFromConsensus(result)
} }
func IsSyncCommitteeUpdate(update *v2.LightClientUpdate) bool {
nextSyncCommitteeBranch := make([][]byte, fieldparams.SyncCommitteeBranchDepth)
return !reflect.DeepEqual(update.NextSyncCommitteeBranch, nextSyncCommitteeBranch)
}
func IsFinalityUpdate(update *v2.LightClientUpdate) bool {
finalityBranch := make([][]byte, lightclient.FinalityBranchNumOfLeaves)
return !reflect.DeepEqual(update.FinalityBranch, finalityBranch)
}
func IsBetterUpdate(newUpdate, oldUpdate *v2.LightClientUpdate) (bool, error) {
maxActiveParticipants := newUpdate.SyncAggregate.SyncCommitteeBits.Len()
newNumActiveParticipants := newUpdate.SyncAggregate.SyncCommitteeBits.Count()
oldNumActiveParticipants := oldUpdate.SyncAggregate.SyncCommitteeBits.Count()
newHasSupermajority := newNumActiveParticipants*3 >= maxActiveParticipants*2
oldHasSupermajority := oldNumActiveParticipants*3 >= maxActiveParticipants*2
if newHasSupermajority != oldHasSupermajority {
return newHasSupermajority, nil
}
if !newHasSupermajority && newNumActiveParticipants != oldNumActiveParticipants {
return newNumActiveParticipants > oldNumActiveParticipants, nil
}
newUpdateAttestedHeaderBeacon, err := newUpdate.AttestedHeader.GetBeacon()
if err != nil {
return false, errors.Wrap(err, "could not get attested header beacon")
}
oldUpdateAttestedHeaderBeacon, err := oldUpdate.AttestedHeader.GetBeacon()
if err != nil {
return false, errors.Wrap(err, "could not get attested header beacon")
}
// Compare presence of relevant sync committee
newHasRelevantSyncCommittee := IsSyncCommitteeUpdate(newUpdate) && (slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(newUpdate.SignatureSlot)))
oldHasRelevantSyncCommittee := IsSyncCommitteeUpdate(oldUpdate) && (slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdate.SignatureSlot)))
if newHasRelevantSyncCommittee != oldHasRelevantSyncCommittee {
return newHasRelevantSyncCommittee, nil
}
// Compare indication of any finality
newHasFinality := IsFinalityUpdate(newUpdate)
oldHasFinality := IsFinalityUpdate(oldUpdate)
if newHasFinality != oldHasFinality {
return newHasFinality, nil
}
newUpdateFinalizedHeaderBeacon, err := newUpdate.FinalizedHeader.GetBeacon()
if err != nil {
return false, errors.Wrap(err, "could not get finalized header beacon")
}
oldUpdateFinalizedHeaderBeacon, err := oldUpdate.FinalizedHeader.GetBeacon()
if err != nil {
return false, errors.Wrap(err, "could not get finalized header beacon")
}
// Compare sync committee finality
if newHasFinality {
newHasSyncCommitteeFinality := slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateFinalizedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot))
oldHasSyncCommitteeFinality := slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateFinalizedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot))
if newHasSyncCommitteeFinality != oldHasSyncCommitteeFinality {
return newHasSyncCommitteeFinality, nil
}
}
// Tiebreaker 1: Sync committee participation beyond supermajority
if newNumActiveParticipants != oldNumActiveParticipants {
return newNumActiveParticipants > oldNumActiveParticipants, nil
}
// Tiebreaker 2: Prefer older data (fewer changes to best)
if newUpdateAttestedHeaderBeacon.Slot != oldUpdateAttestedHeaderBeacon.Slot {
return newUpdateAttestedHeaderBeacon.Slot < oldUpdateAttestedHeaderBeacon.Slot, nil
}
return newUpdate.SignatureSlot < oldUpdate.SignatureSlot, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,9 @@ import (
) )
type Server struct { type Server struct {
Blocker lookup.Blocker Blocker lookup.Blocker
Stater lookup.Stater Stater lookup.Stater
HeadFetcher blockchain.HeadFetcher HeadFetcher blockchain.HeadFetcher
BeaconDB db.HeadAccessDatabase ChainInfoFetcher blockchain.ChainInfoFetcher
BeaconDB db.HeadAccessDatabase
} }

View File

@@ -240,23 +240,13 @@ func PayloadProof(ctx context.Context, block interfaces.ReadOnlyBeaconBlock) ([]
return nil, errors.New("failed to cast block body") return nil, errors.New("failed to cast block body")
} }
blockBodyFieldRoots, err := ComputeBlockBodyFieldRoots(ctx, blockBody) fieldRoots, err := ComputeBlockBodyFieldRoots(ctx, blockBody)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blockBodyFieldRootsTrie := stateutil.Merkleize(blockBodyFieldRoots) fieldRootsTrie := stateutil.Merkleize(fieldRoots)
blockBodyProof := trie.ProofFromMerkleLayers(blockBodyFieldRootsTrie, payloadFieldIndex) proof := trie.ProofFromMerkleLayers(fieldRootsTrie, payloadFieldIndex)
beaconBlockFieldRoots, err := ComputeBlockFieldRoots(ctx, block) return proof, nil
if err != nil {
return nil, err
}
beaconBlockFieldRootsTrie := stateutil.Merkleize(beaconBlockFieldRoots)
beaconBlockProof := trie.ProofFromMerkleLayers(beaconBlockFieldRootsTrie, bodyFieldIndex)
finalProof := append(blockBodyProof, beaconBlockProof...)
return finalProof, nil
} }

View File

@@ -27,9 +27,12 @@ type LightClientBootstrap interface {
ssz.Marshaler ssz.Marshaler
Version() int Version() int
Header() LightClientHeader Header() LightClientHeader
SetHeader(header LightClientHeader) error
CurrentSyncCommittee() *pb.SyncCommittee CurrentSyncCommittee() *pb.SyncCommittee
SetCurrentSyncCommittee(sc *pb.SyncCommittee) error
CurrentSyncCommitteeBranch() (LightClientSyncCommitteeBranch, error) CurrentSyncCommitteeBranch() (LightClientSyncCommitteeBranch, error)
CurrentSyncCommitteeBranchElectra() (LightClientSyncCommitteeBranchElectra, error) CurrentSyncCommitteeBranchElectra() (LightClientSyncCommitteeBranchElectra, error)
SetCurrentSyncCommitteeBranch(branch [][]byte) error
} }
type LightClientUpdate interface { type LightClientUpdate interface {
@@ -56,6 +59,7 @@ type LightClientUpdate interface {
type LightClientFinalityUpdate interface { type LightClientFinalityUpdate interface {
ssz.Marshaler ssz.Marshaler
ssz.Unmarshaler
Proto() proto.Message Proto() proto.Message
Version() int Version() int
AttestedHeader() LightClientHeader AttestedHeader() LightClientHeader
@@ -68,6 +72,7 @@ type LightClientFinalityUpdate interface {
type LightClientOptimisticUpdate interface { type LightClientOptimisticUpdate interface {
ssz.Marshaler ssz.Marshaler
ssz.Unmarshaler
Proto() proto.Message Proto() proto.Message
Version() int Version() int
AttestedHeader() LightClientHeader AttestedHeader() LightClientHeader

View File

@@ -41,10 +41,16 @@ func NewWrappedBootstrapAltair(p *pb.LightClientBootstrapAltair) (interfaces.Lig
if p == nil { if p == nil {
return nil, consensustypes.ErrNilObjectWrapped return nil, consensustypes.ErrNilObjectWrapped
} }
header, err := NewWrappedHeader(p.Header)
if err != nil { var header interfaces.LightClientHeader
return nil, err var err error
if p.Header != nil {
header, err = NewWrappedHeader(p.Header)
if err != nil {
return nil, err
}
} }
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch]( branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee", "sync committee",
p.CurrentSyncCommitteeBranch, p.CurrentSyncCommitteeBranch,
@@ -81,14 +87,42 @@ func (h *bootstrapAltair) Header() interfaces.LightClientHeader {
return h.header return h.header
} }
func (h *bootstrapAltair) SetHeader(header interfaces.LightClientHeader) error {
p, ok := (header.Proto()).(*pb.LightClientHeaderAltair)
if !ok {
return fmt.Errorf("header type %T is not %T", p, &pb.LightClientHeaderAltair{})
}
h.p.Header = p
h.header = header
return nil
}
func (h *bootstrapAltair) CurrentSyncCommittee() *pb.SyncCommittee { func (h *bootstrapAltair) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee return h.p.CurrentSyncCommittee
} }
func (h *bootstrapAltair) SetCurrentSyncCommittee(sc *pb.SyncCommittee) error {
h.p.CurrentSyncCommittee = sc
return nil
}
func (h *bootstrapAltair) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { func (h *bootstrapAltair) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) {
return h.currentSyncCommitteeBranch, nil return h.currentSyncCommitteeBranch, nil
} }
func (h *bootstrapAltair) SetCurrentSyncCommitteeBranch(branch [][]byte) error {
if len(branch) != fieldparams.SyncCommitteeBranchDepth {
return fmt.Errorf("branch length %d is not %d", len(branch), fieldparams.SyncCommitteeBranchDepth)
}
newBranch := [fieldparams.SyncCommitteeBranchDepth][32]byte{}
for i, root := range branch {
copy(newBranch[i][:], root)
}
h.currentSyncCommitteeBranch = newBranch
h.p.CurrentSyncCommitteeBranch = branch
return nil
}
func (h *bootstrapAltair) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { func (h *bootstrapAltair) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) {
return [6][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranchElectra", version.Altair) return [6][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranchElectra", version.Altair)
} }
@@ -105,10 +139,16 @@ func NewWrappedBootstrapCapella(p *pb.LightClientBootstrapCapella) (interfaces.L
if p == nil { if p == nil {
return nil, consensustypes.ErrNilObjectWrapped return nil, consensustypes.ErrNilObjectWrapped
} }
header, err := NewWrappedHeader(p.Header)
if err != nil { var header interfaces.LightClientHeader
return nil, err var err error
if p.Header != nil {
header, err = NewWrappedHeader(p.Header)
if err != nil {
return nil, err
}
} }
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch]( branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee", "sync committee",
p.CurrentSyncCommitteeBranch, p.CurrentSyncCommitteeBranch,
@@ -145,14 +185,42 @@ func (h *bootstrapCapella) Header() interfaces.LightClientHeader {
return h.header return h.header
} }
func (h *bootstrapCapella) SetHeader(header interfaces.LightClientHeader) error {
p, ok := (header.Proto()).(*pb.LightClientHeaderCapella)
if !ok {
return fmt.Errorf("header type %T is not %T", p, &pb.LightClientHeaderCapella{})
}
h.p.Header = p
h.header = header
return nil
}
func (h *bootstrapCapella) CurrentSyncCommittee() *pb.SyncCommittee { func (h *bootstrapCapella) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee return h.p.CurrentSyncCommittee
} }
func (h *bootstrapCapella) SetCurrentSyncCommittee(sc *pb.SyncCommittee) error {
h.p.CurrentSyncCommittee = sc
return nil
}
func (h *bootstrapCapella) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { func (h *bootstrapCapella) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) {
return h.currentSyncCommitteeBranch, nil return h.currentSyncCommitteeBranch, nil
} }
func (h *bootstrapCapella) SetCurrentSyncCommitteeBranch(branch [][]byte) error {
if len(branch) != fieldparams.SyncCommitteeBranchDepth {
return fmt.Errorf("branch length %d is not %d", len(branch), fieldparams.SyncCommitteeBranchDepth)
}
newBranch := [fieldparams.SyncCommitteeBranchDepth][32]byte{}
for i, root := range branch {
copy(newBranch[i][:], root)
}
h.currentSyncCommitteeBranch = newBranch
h.p.CurrentSyncCommitteeBranch = branch
return nil
}
func (h *bootstrapCapella) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { func (h *bootstrapCapella) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) {
return [6][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranchElectra", version.Capella) return [6][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranchElectra", version.Capella)
} }
@@ -169,10 +237,16 @@ func NewWrappedBootstrapDeneb(p *pb.LightClientBootstrapDeneb) (interfaces.Light
if p == nil { if p == nil {
return nil, consensustypes.ErrNilObjectWrapped return nil, consensustypes.ErrNilObjectWrapped
} }
header, err := NewWrappedHeader(p.Header)
if err != nil { var header interfaces.LightClientHeader
return nil, err var err error
if p.Header != nil {
header, err = NewWrappedHeader(p.Header)
if err != nil {
return nil, err
}
} }
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch]( branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee", "sync committee",
p.CurrentSyncCommitteeBranch, p.CurrentSyncCommitteeBranch,
@@ -209,14 +283,42 @@ func (h *bootstrapDeneb) Header() interfaces.LightClientHeader {
return h.header return h.header
} }
func (h *bootstrapDeneb) SetHeader(header interfaces.LightClientHeader) error {
p, ok := (header.Proto()).(*pb.LightClientHeaderDeneb)
if !ok {
return fmt.Errorf("header type %T is not %T", p, &pb.LightClientHeaderDeneb{})
}
h.p.Header = p
h.header = header
return nil
}
func (h *bootstrapDeneb) CurrentSyncCommittee() *pb.SyncCommittee { func (h *bootstrapDeneb) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee return h.p.CurrentSyncCommittee
} }
func (h *bootstrapDeneb) SetCurrentSyncCommittee(sc *pb.SyncCommittee) error {
h.p.CurrentSyncCommittee = sc
return nil
}
func (h *bootstrapDeneb) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { func (h *bootstrapDeneb) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) {
return h.currentSyncCommitteeBranch, nil return h.currentSyncCommitteeBranch, nil
} }
func (h *bootstrapDeneb) SetCurrentSyncCommitteeBranch(branch [][]byte) error {
if len(branch) != fieldparams.SyncCommitteeBranchDepth {
return fmt.Errorf("branch length %d is not %d", len(branch), fieldparams.SyncCommitteeBranchDepth)
}
newBranch := [fieldparams.SyncCommitteeBranchDepth][32]byte{}
for i, root := range branch {
copy(newBranch[i][:], root)
}
h.currentSyncCommitteeBranch = newBranch
h.p.CurrentSyncCommitteeBranch = branch
return nil
}
func (h *bootstrapDeneb) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { func (h *bootstrapDeneb) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) {
return [6][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranchElectra", version.Deneb) return [6][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranchElectra", version.Deneb)
} }
@@ -233,10 +335,16 @@ func NewWrappedBootstrapElectra(p *pb.LightClientBootstrapElectra) (interfaces.L
if p == nil { if p == nil {
return nil, consensustypes.ErrNilObjectWrapped return nil, consensustypes.ErrNilObjectWrapped
} }
header, err := NewWrappedHeader(p.Header)
if err != nil { var header interfaces.LightClientHeader
return nil, err var err error
if p.Header != nil {
header, err = NewWrappedHeader(p.Header)
if err != nil {
return nil, err
}
} }
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranchElectra]( branch, err := createBranch[interfaces.LightClientSyncCommitteeBranchElectra](
"sync committee", "sync committee",
p.CurrentSyncCommitteeBranch, p.CurrentSyncCommitteeBranch,
@@ -273,14 +381,42 @@ func (h *bootstrapElectra) Header() interfaces.LightClientHeader {
return h.header return h.header
} }
func (h *bootstrapElectra) SetHeader(header interfaces.LightClientHeader) error {
p, ok := (header.Proto()).(*pb.LightClientHeaderDeneb)
if !ok {
return fmt.Errorf("header type %T is not %T", p, &pb.LightClientHeaderDeneb{})
}
h.p.Header = p
h.header = header
return nil
}
func (h *bootstrapElectra) CurrentSyncCommittee() *pb.SyncCommittee { func (h *bootstrapElectra) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee return h.p.CurrentSyncCommittee
} }
func (h *bootstrapElectra) SetCurrentSyncCommittee(sc *pb.SyncCommittee) error {
h.p.CurrentSyncCommittee = sc
return nil
}
func (h *bootstrapElectra) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { func (h *bootstrapElectra) CurrentSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) {
return [5][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranch", version.Electra) return [5][32]byte{}, consensustypes.ErrNotSupported("CurrentSyncCommitteeBranch", version.Electra)
} }
func (h *bootstrapElectra) SetCurrentSyncCommitteeBranch(branch [][]byte) error {
if len(branch) != fieldparams.SyncCommitteeBranchDepthElectra {
return fmt.Errorf("branch length %d is not %d", len(branch), fieldparams.SyncCommitteeBranchDepthElectra)
}
newBranch := [fieldparams.SyncCommitteeBranchDepthElectra][32]byte{}
for i, root := range branch {
copy(newBranch[i][:], root)
}
h.currentSyncCommitteeBranch = newBranch
h.p.CurrentSyncCommitteeBranch = branch
return nil
}
func (h *bootstrapElectra) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { func (h *bootstrapElectra) CurrentSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) {
return h.currentSyncCommitteeBranch, nil return h.currentSyncCommitteeBranch, nil
} }

View File

@@ -139,6 +139,23 @@ func (u *finalityUpdateAltair) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *finalityUpdateAltair) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientFinalityUpdateAltair{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedFinalityUpdateAltair(p)
if err != nil {
return err
}
update, ok := updateInterface.(*finalityUpdateAltair)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *finalityUpdateAltair) Proto() proto.Message { func (u *finalityUpdateAltair) Proto() proto.Message {
return u.p return u.p
} }
@@ -221,6 +238,23 @@ func (u *finalityUpdateCapella) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *finalityUpdateCapella) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientFinalityUpdateCapella{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedFinalityUpdateCapella(p)
if err != nil {
return err
}
update, ok := updateInterface.(*finalityUpdateCapella)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *finalityUpdateCapella) Proto() proto.Message { func (u *finalityUpdateCapella) Proto() proto.Message {
return u.p return u.p
} }
@@ -303,6 +337,23 @@ func (u *finalityUpdateDeneb) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *finalityUpdateDeneb) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientFinalityUpdateDeneb{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedFinalityUpdateDeneb(p)
if err != nil {
return err
}
update, ok := updateInterface.(*finalityUpdateDeneb)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *finalityUpdateDeneb) Proto() proto.Message { func (u *finalityUpdateDeneb) Proto() proto.Message {
return u.p return u.p
} }
@@ -386,6 +437,23 @@ func (u *finalityUpdateElectra) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *finalityUpdateElectra) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientFinalityUpdateElectra{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedFinalityUpdateElectra(p)
if err != nil {
return err
}
update, ok := updateInterface.(*finalityUpdateElectra)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *finalityUpdateElectra) Proto() proto.Message { func (u *finalityUpdateElectra) Proto() proto.Message {
return u.p return u.p
} }

View File

@@ -104,6 +104,23 @@ func (u *optimisticUpdateAltair) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *optimisticUpdateAltair) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientOptimisticUpdateAltair{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedOptimisticUpdateAltair(p)
if err != nil {
return err
}
update, ok := updateInterface.(*optimisticUpdateAltair)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *optimisticUpdateAltair) Proto() proto.Message { func (u *optimisticUpdateAltair) Proto() proto.Message {
return u.p return u.p
} }
@@ -158,6 +175,23 @@ func (u *optimisticUpdateCapella) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *optimisticUpdateCapella) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientOptimisticUpdateCapella{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedOptimisticUpdateCapella(p)
if err != nil {
return err
}
update, ok := updateInterface.(*optimisticUpdateCapella)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *optimisticUpdateCapella) Proto() proto.Message { func (u *optimisticUpdateCapella) Proto() proto.Message {
return u.p return u.p
} }
@@ -212,6 +246,23 @@ func (u *optimisticUpdateDeneb) SizeSSZ() int {
return u.p.SizeSSZ() return u.p.SizeSSZ()
} }
func (u *optimisticUpdateDeneb) UnmarshalSSZ(buf []byte) error {
p := &pb.LightClientOptimisticUpdateDeneb{}
if err := p.UnmarshalSSZ(buf); err != nil {
return err
}
updateInterface, err := NewWrappedOptimisticUpdateDeneb(p)
if err != nil {
return err
}
update, ok := updateInterface.(*optimisticUpdateDeneb)
if !ok {
return fmt.Errorf("unexpected update type %T", updateInterface)
}
*u = *update
return nil
}
func (u *optimisticUpdateDeneb) Proto() proto.Message { func (u *optimisticUpdateDeneb) Proto() proto.Message {
return u.p return u.p
} }

View File

@@ -168,6 +168,10 @@ func (u *updateAltair) FinalityBranch() (interfaces.LightClientFinalityBranch, e
return u.finalityBranch, nil return u.finalityBranch, nil
} }
func (u *updateAltair) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return interfaces.LightClientFinalityBranchElectra{}, consensustypes.ErrNotSupported("FinalityBranchElectra", version.Altair)
}
func (u *updateAltair) SetFinalityBranch(branch [][]byte) error { func (u *updateAltair) SetFinalityBranch(branch [][]byte) error {
b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth)
if err != nil { if err != nil {
@@ -178,10 +182,6 @@ func (u *updateAltair) SetFinalityBranch(branch [][]byte) error {
return nil return nil
} }
func (u *updateAltair) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return interfaces.LightClientFinalityBranchElectra{}, consensustypes.ErrNotSupported("FinalityBranchElectra", version.Altair)
}
func (u *updateAltair) SyncAggregate() *pb.SyncAggregate { func (u *updateAltair) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate return u.p.SyncAggregate
} }
@@ -335,6 +335,10 @@ func (u *updateCapella) FinalityBranch() (interfaces.LightClientFinalityBranch,
return u.finalityBranch, nil return u.finalityBranch, nil
} }
func (u *updateCapella) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return interfaces.LightClientFinalityBranchElectra{}, consensustypes.ErrNotSupported("FinalityBranchElectra", u.Version())
}
func (u *updateCapella) SetFinalityBranch(branch [][]byte) error { func (u *updateCapella) SetFinalityBranch(branch [][]byte) error {
b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth)
if err != nil { if err != nil {
@@ -345,10 +349,6 @@ func (u *updateCapella) SetFinalityBranch(branch [][]byte) error {
return nil return nil
} }
func (u *updateCapella) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return interfaces.LightClientFinalityBranchElectra{}, consensustypes.ErrNotSupported("FinalityBranchElectra", u.Version())
}
func (u *updateCapella) SyncAggregate() *pb.SyncAggregate { func (u *updateCapella) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate return u.p.SyncAggregate
} }
@@ -502,6 +502,10 @@ func (u *updateDeneb) FinalityBranch() (interfaces.LightClientFinalityBranch, er
return u.finalityBranch, nil return u.finalityBranch, nil
} }
func (u *updateDeneb) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return interfaces.LightClientFinalityBranchElectra{}, consensustypes.ErrNotSupported("FinalityBranchElectra", u.Version())
}
func (u *updateDeneb) SetFinalityBranch(branch [][]byte) error { func (u *updateDeneb) SetFinalityBranch(branch [][]byte) error {
b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth)
if err != nil { if err != nil {
@@ -512,10 +516,6 @@ func (u *updateDeneb) SetFinalityBranch(branch [][]byte) error {
return nil return nil
} }
func (u *updateDeneb) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return interfaces.LightClientFinalityBranchElectra{}, consensustypes.ErrNotSupported("FinalityBranchElectra", u.Version())
}
func (u *updateDeneb) SyncAggregate() *pb.SyncAggregate { func (u *updateDeneb) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate return u.p.SyncAggregate
} }
@@ -670,6 +670,10 @@ func (u *updateElectra) FinalityBranch() (interfaces.LightClientFinalityBranch,
return interfaces.LightClientFinalityBranch{}, consensustypes.ErrNotSupported("FinalityBranch", u.Version()) return interfaces.LightClientFinalityBranch{}, consensustypes.ErrNotSupported("FinalityBranch", u.Version())
} }
func (u *updateElectra) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return u.finalityBranch, nil
}
func (u *updateElectra) SetFinalityBranch(branch [][]byte) error { func (u *updateElectra) SetFinalityBranch(branch [][]byte) error {
b, err := createBranch[interfaces.LightClientFinalityBranchElectra]("finality", branch, fieldparams.FinalityBranchDepthElectra) b, err := createBranch[interfaces.LightClientFinalityBranchElectra]("finality", branch, fieldparams.FinalityBranchDepthElectra)
if err != nil { if err != nil {
@@ -680,10 +684,6 @@ func (u *updateElectra) SetFinalityBranch(branch [][]byte) error {
return nil return nil
} }
func (u *updateElectra) FinalityBranchElectra() (interfaces.LightClientFinalityBranchElectra, error) {
return u.finalityBranch, nil
}
func (u *updateElectra) SyncAggregate() *pb.SyncAggregate { func (u *updateElectra) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate return u.p.SyncAggregate
} }

View File

@@ -14,9 +14,8 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz" "github.com/prysmaticlabs/prysm/v5/encoding/ssz"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require" "github.com/prysmaticlabs/prysm/v5/testing/require"
) )
@@ -47,14 +46,14 @@ func (l *TestLightClient) SetupTestCapella(blinded bool) *TestLightClient {
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockCapella()) finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockCapella())
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedBlock.SetSlot(1) finalizedBlock.SetSlot(primitives.Slot(params.BeaconConfig().CapellaForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)))
finalizedHeader, err := finalizedBlock.Header() finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot() finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err) require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{ require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().CapellaForkEpoch - 10, Epoch: params.BeaconConfig().CapellaForkEpoch,
Root: finalizedRoot[:], Root: finalizedRoot[:],
})) }))
@@ -262,25 +261,33 @@ func (l *TestLightClient) SetupTestCapellaFinalizedBlockAltair(blinded bool) *Te
func (l *TestLightClient) SetupTestAltair() *TestLightClient { func (l *TestLightClient) SetupTestAltair() *TestLightClient {
ctx := context.Background() ctx := context.Background()
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1) slot := primitives.Slot(uint64(params.BeaconConfig().AltairForkEpoch) * uint64(params.BeaconConfig().SlotsPerEpoch)).Add(1)
attestedState, err := NewBeaconStateAltair() attestedState, err := NewBeaconStateAltair()
require.NoError(l.T, err) require.NoError(l.T, err)
err = attestedState.SetSlot(slot) err = attestedState.SetSlot(slot)
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockAltair()) finalizedState, err := NewBeaconStateAltair()
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedBlock.SetSlot(1) err = finalizedState.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header() require.NoError(l.T, err)
finalizedStateRoot, err := finalizedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
SignedFinalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockAltair())
require.NoError(l.T, err)
SignedFinalizedBlock.SetSlot(1)
SignedFinalizedBlock.SetStateRoot(finalizedStateRoot[:])
finalizedHeader, err := SignedFinalizedBlock.Header()
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot() finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err) require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{ finalizedCheckpoint := &ethpb.Checkpoint{
Epoch: params.BeaconConfig().AltairForkEpoch - 10, Epoch: params.BeaconConfig().AltairForkEpoch - 10,
Root: finalizedRoot[:], Root: finalizedRoot[:],
})) }
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(finalizedCheckpoint))
parent := NewBeaconBlockAltair() parent := NewBeaconBlockAltair()
parent.Block.Slot = slot parent.Block.Slot = slot
@@ -338,7 +345,7 @@ func (l *TestLightClient) SetupTestAltair() *TestLightClient {
l.AttestedState = attestedState l.AttestedState = attestedState
l.Block = signedBlock l.Block = signedBlock
l.Ctx = ctx l.Ctx = ctx
l.FinalizedBlock = finalizedBlock l.FinalizedBlock = SignedFinalizedBlock
l.AttestedBlock = signedParent l.AttestedBlock = signedParent
return l return l
@@ -441,14 +448,14 @@ func (l *TestLightClient) SetupTestDeneb(blinded bool) *TestLightClient {
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockDeneb()) finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockDeneb())
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedBlock.SetSlot(1) finalizedBlock.SetSlot(primitives.Slot(params.BeaconConfig().DenebForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)))
finalizedHeader, err := finalizedBlock.Header() finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot() finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err) require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{ require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().DenebForkEpoch - 10, Epoch: params.BeaconConfig().DenebForkEpoch,
Root: finalizedRoot[:], Root: finalizedRoot[:],
})) }))
@@ -665,14 +672,14 @@ func (l *TestLightClient) SetupTestDenebFinalizedBlockCapella(blinded bool) *Tes
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockCapella()) finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockCapella())
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedBlock.SetSlot(1) finalizedBlock.SetSlot(primitives.Slot(params.BeaconConfig().DenebForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Sub(15))
finalizedHeader, err := finalizedBlock.Header() finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err) require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot() finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err) require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{ require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().CapellaForkEpoch - 10, Epoch: params.BeaconConfig().DenebForkEpoch - 1,
Root: finalizedRoot[:], Root: finalizedRoot[:],
})) }))
@@ -765,9 +772,8 @@ func (l *TestLightClient) SetupTestDenebFinalizedBlockCapella(blinded bool) *Tes
return l return l
} }
func (l *TestLightClient) CheckAttestedHeader(container *ethpbv2.LightClientHeaderContainer) { func (l *TestLightClient) CheckAttestedHeader(header interfaces.LightClientHeader) {
updateAttestedHeaderBeacon, err := container.GetBeacon() updateAttestedHeaderBeacon := header.Beacon()
require.NoError(l.T, err)
testAttestedHeader, err := l.AttestedBlock.Header() testAttestedHeader, err := l.AttestedBlock.Header()
require.NoError(l.T, err) require.NoError(l.T, err)
require.Equal(l.T, l.AttestedBlock.Block().Slot(), updateAttestedHeaderBeacon.Slot, "Attested block slot is not equal") require.Equal(l.T, l.AttestedBlock.Block().Slot(), updateAttestedHeaderBeacon.Slot, "Attested block slot is not equal")
@@ -820,16 +826,16 @@ func (l *TestLightClient) CheckAttestedHeader(container *ethpbv2.LightClientHead
WithdrawalsRoot: withdrawalsRoot, WithdrawalsRoot: withdrawalsRoot,
} }
updateAttestedHeaderExecution, err := container.GetExecutionHeaderCapella() updateAttestedHeaderExecution, err := header.Execution()
require.NoError(l.T, err) require.NoError(l.T, err)
require.DeepSSZEqual(l.T, execution, updateAttestedHeaderExecution, "Attested Block Execution is not equal") require.DeepSSZEqual(l.T, execution, updateAttestedHeaderExecution.Proto(), "Attested Block Execution is not equal")
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.AttestedBlock.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.AttestedBlock.Block())
require.NoError(l.T, err) require.NoError(l.T, err)
updateAttestedHeaderExecutionBranch, err := container.GetExecutionBranch() updateAttestedHeaderExecutionBranch, err := header.ExecutionBranch()
require.NoError(l.T, err) require.NoError(l.T, err)
for i, leaf := range updateAttestedHeaderExecutionBranch { for i, leaf := range updateAttestedHeaderExecutionBranch {
require.DeepSSZEqual(l.T, executionPayloadProof[i], leaf, "Leaf is not equal") require.DeepSSZEqual(l.T, executionPayloadProof[i], leaf[:], "Leaf is not equal")
} }
} }
@@ -874,21 +880,21 @@ func (l *TestLightClient) CheckAttestedHeader(container *ethpbv2.LightClientHead
WithdrawalsRoot: withdrawalsRoot, WithdrawalsRoot: withdrawalsRoot,
} }
updateAttestedHeaderExecution, err := container.GetExecutionHeaderDeneb() updateAttestedHeaderExecution, err := header.Execution()
require.NoError(l.T, err) require.NoError(l.T, err)
require.DeepSSZEqual(l.T, execution, updateAttestedHeaderExecution, "Attested Block Execution is not equal") require.DeepSSZEqual(l.T, execution, updateAttestedHeaderExecution.Proto(), "Attested Block Execution is not equal")
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.AttestedBlock.Block()) executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.AttestedBlock.Block())
require.NoError(l.T, err) require.NoError(l.T, err)
updateAttestedHeaderExecutionBranch, err := container.GetExecutionBranch() updateAttestedHeaderExecutionBranch, err := header.ExecutionBranch()
require.NoError(l.T, err) require.NoError(l.T, err)
for i, leaf := range updateAttestedHeaderExecutionBranch { for i, leaf := range updateAttestedHeaderExecutionBranch {
require.DeepSSZEqual(l.T, executionPayloadProof[i], leaf, "Leaf is not equal") require.DeepSSZEqual(l.T, executionPayloadProof[i], leaf[:], "Leaf is not equal")
} }
} }
} }
func (l *TestLightClient) CheckSyncAggregate(sa *ethpbv1.SyncAggregate) { func (l *TestLightClient) CheckSyncAggregate(sa *pb.SyncAggregate) {
syncAggregate, err := l.Block.Block().Body().SyncAggregate() syncAggregate, err := l.Block.Block().Body().SyncAggregate()
require.NoError(l.T, err) require.NoError(l.T, err)
require.DeepSSZEqual(l.T, syncAggregate.SyncCommitteeBits, sa.SyncCommitteeBits, "SyncAggregate bits is not equal") require.DeepSSZEqual(l.T, syncAggregate.SyncCommitteeBits, sa.SyncCommitteeBits, "SyncAggregate bits is not equal")