Refactor light client functions (#14434)

* Use correct types in light client functions

* conversions

* more refactoring

* test fixes

* changelog

* error fix

* revert test changes

* revert test skip

* Update api/server/structs/conversions_lightclient.go

Co-authored-by: Rupam Dey <117000803+rupam-04@users.noreply.github.com>

* use BlockToLightClientHeader

* reviewer suggestion

* Revert "use BlockToLightClientHeader"

This reverts commit f3df56ded5.

---------

Co-authored-by: Rupam Dey <117000803+rupam-04@users.noreply.github.com>
This commit is contained in:
Radosław Kapka
2024-09-13 18:08:28 -04:00
committed by GitHub
parent ed6f69e868
commit 7ac3c01b5b
15 changed files with 546 additions and 590 deletions

View File

@@ -36,6 +36,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Clean up `ProposeBlock` for validator client to reduce cognitive scoring and enable further changes.
- Updated k8s-io/client-go to v0.30.4 and k8s-io/apimachinery to v0.30.4
- Migrated tracing library from opencensus to opentelemetry for both the beacon node and validator.
- Refactored light client code to make it more readable and make future PRs easier.
### Deprecated
- `--disable-grpc-gateway` flag is deprecated due to grpc gateway removal.

View File

@@ -34,6 +34,9 @@ go_library(
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//proto/engine/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",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",

View File

@@ -1,3 +1,122 @@
package structs
//
import (
"encoding/json"
"fmt"
"strconv"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/proto/migration"
)
func LightClientUpdateFromConsensus(update *v2.LightClientUpdate) (*LightClientUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header")
}
finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal finalized light client header")
}
return &LightClientUpdate{
AttestedHeader: attestedHeader,
NextSyncCommittee: SyncCommitteeFromConsensus(migration.V2SyncCommitteeToV1Alpha1(update.NextSyncCommittee)),
NextSyncCommitteeBranch: branchToJSON(update.NextSyncCommitteeBranch),
FinalizedHeader: finalizedHeader,
FinalityBranch: branchToJSON(update.FinalityBranch),
SyncAggregate: syncAggregateToJSON(update.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10),
}, nil
}
func LightClientFinalityUpdateFromConsensus(update *v2.LightClientFinalityUpdate) (*LightClientFinalityUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header")
}
finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal finalized light client header")
}
return &LightClientFinalityUpdate{
AttestedHeader: attestedHeader,
FinalizedHeader: finalizedHeader,
FinalityBranch: branchToJSON(update.FinalityBranch),
SyncAggregate: syncAggregateToJSON(update.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10),
}, nil
}
func LightClientOptimisticUpdateFromConsensus(update *v2.LightClientOptimisticUpdate) (*LightClientOptimisticUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header")
}
return &LightClientOptimisticUpdate{
AttestedHeader: attestedHeader,
SyncAggregate: syncAggregateToJSON(update.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10),
}, nil
}
func branchToJSON(branchBytes [][]byte) []string {
if branchBytes == nil {
return nil
}
branch := make([]string, len(branchBytes))
for i, root := range branchBytes {
branch[i] = hexutil.Encode(root)
}
return branch
}
func syncAggregateToJSON(input *v1.SyncAggregate) *SyncAggregate {
return &SyncAggregate{
SyncCommitteeBits: hexutil.Encode(input.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(input.SyncCommitteeSignature),
}
}
func lightClientHeaderContainerToJSON(container *v2.LightClientHeaderContainer) (json.RawMessage, error) {
beacon, err := container.GetBeacon()
if err != nil {
return nil, errors.Wrap(err, "could not get beacon block header")
}
var header any
switch t := (container.Header).(type) {
case *v2.LightClientHeaderContainer_HeaderAltair:
header = &LightClientHeader{Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon))}
case *v2.LightClientHeaderContainer_HeaderCapella:
execution, err := ExecutionPayloadHeaderCapellaFromConsensus(t.HeaderCapella.Execution)
if err != nil {
return nil, err
}
header = &LightClientHeaderCapella{
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)),
Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderCapella.ExecutionBranch),
}
case *v2.LightClientHeaderContainer_HeaderDeneb:
execution, err := ExecutionPayloadHeaderDenebFromConsensus(t.HeaderDeneb.Execution)
if err != nil {
return nil, err
}
header = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)),
Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderDeneb.ExecutionBranch),
}
default:
return nil, fmt.Errorf("unsupported header type %T", t)
}
return json.Marshal(header)
}

View File

@@ -96,21 +96,7 @@ type LightClientFinalityUpdateEvent struct {
Data *LightClientFinalityUpdate `json:"data"`
}
type LightClientFinalityUpdate struct {
AttestedHeader *BeaconBlockHeader `json:"attested_header"`
FinalizedHeader *BeaconBlockHeader `json:"finalized_header"`
FinalityBranch []string `json:"finality_branch"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}
type LightClientOptimisticUpdateEvent struct {
Version string `json:"version"`
Data *LightClientOptimisticUpdate `json:"data"`
}
type LightClientOptimisticUpdate struct {
AttestedHeader *BeaconBlockHeader `json:"attested_header"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}

View File

@@ -24,11 +24,6 @@ type LightClientBootstrap struct {
CurrentSyncCommitteeBranch []string `json:"current_sync_committee_branch"`
}
type LightClientBootstrapResponse struct {
Version string `json:"version"`
Data *LightClientBootstrap `json:"data"`
}
type LightClientUpdate struct {
AttestedHeader json.RawMessage `json:"attested_header"`
NextSyncCommittee *SyncCommittee `json:"next_sync_committee,omitempty"`
@@ -39,11 +34,40 @@ type LightClientUpdate struct {
SignatureSlot string `json:"signature_slot"`
}
type LightClientUpdateWithVersion struct {
type LightClientFinalityUpdate struct {
AttestedHeader json.RawMessage `json:"attested_header"`
FinalizedHeader json.RawMessage `json:"finalized_header"`
FinalityBranch []string `json:"finality_branch"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}
type LightClientOptimisticUpdate struct {
AttestedHeader json.RawMessage `json:"attested_header"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}
type LightClientBootstrapResponse struct {
Version string `json:"version"`
Data *LightClientBootstrap `json:"data"`
}
type LightClientUpdateResponse struct {
Version string `json:"version"`
Data *LightClientUpdate `json:"data"`
}
type LightClientUpdatesByRangeResponse struct {
Updates []*LightClientUpdateWithVersion `json:"updates"`
type LightClientFinalityUpdateResponse struct {
Version string `json:"version"`
Data *LightClientFinalityUpdate `json:"data"`
}
type LightClientOptimisticUpdateResponse struct {
Version string `json:"version"`
Data *LightClientOptimisticUpdate `json:"data"`
}
type LightClientUpdatesByRangeResponse struct {
Updates []*LightClientUpdateResponse `json:"updates"`
}

View File

@@ -193,7 +193,7 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
// Return the result
result := &ethpbv2.LightClientFinalityUpdateWithVersion{
Version: ethpbv2.Version(signed.Version()),
Data: lightclient.CreateLightClientFinalityUpdate(update),
Data: update,
}
// Send event
@@ -227,7 +227,7 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in
// Return the result
result := &ethpbv2.LightClientOptimisticUpdateWithVersion{
Version: ethpbv2.Version(signed.Version()),
Data: lightclient.CreateLightClientOptimisticUpdate(update),
Data: update,
}
return s.cfg.StateNotifier.StateFeed().Send(&feed.Event{

View File

@@ -33,7 +33,6 @@ go_test(
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
],

View File

@@ -2,6 +2,7 @@ package light_client
import (
"bytes"
"context"
"fmt"
"github.com/pkg/errors"
@@ -20,16 +21,15 @@ import (
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"context"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
)
const (
FinalityBranchNumOfLeaves = 6
FinalityBranchNumOfLeaves = 6
executionBranchNumOfLeaves = 4
)
// CreateLightClientFinalityUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_finality_update
// createLightClientFinalityUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_finality_update
// def create_light_client_finality_update(update: LightClientUpdate) -> LightClientFinalityUpdate:
//
// return LightClientFinalityUpdate(
@@ -39,7 +39,7 @@ const (
// sync_aggregate=update.sync_aggregate,
// signature_slot=update.signature_slot,
// )
func CreateLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate {
func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate {
finalityUpdate := &ethpbv2.LightClientFinalityUpdate{
AttestedHeader: update.AttestedHeader,
FinalizedHeader: update.FinalizedHeader,
@@ -51,7 +51,7 @@ func CreateLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2
return finalityUpdate
}
// CreateLightClientOptimisticUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_optimistic_update
// createLightClientOptimisticUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_optimistic_update
// def create_light_client_optimistic_update(update: LightClientUpdate) -> LightClientOptimisticUpdate:
//
// return LightClientOptimisticUpdate(
@@ -59,7 +59,7 @@ func CreateLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2
// sync_aggregate=update.sync_aggregate,
// signature_slot=update.signature_slot,
// )
func CreateLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate {
func createLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate {
optimisticUpdate := &ethpbv2.LightClientOptimisticUpdate{
AttestedHeader: update.AttestedHeader,
SyncAggregate: update.SyncAggregate,
@@ -69,11 +69,98 @@ func CreateLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpb
return optimisticUpdate
}
func NewLightClientFinalityUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*ethpbv2.LightClientFinalityUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
if err != nil {
return nil, err
}
return createLightClientFinalityUpdate(update), nil
}
func NewLightClientOptimisticUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState) (*ethpbv2.LightClientUpdate, error) {
attestedState state.BeaconState,
) (*ethpbv2.LightClientOptimisticUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, nil)
if err != nil {
return nil, err
}
return createLightClientOptimisticUpdate(update), nil
}
// NewLightClientUpdateFromBeaconState implements https://github.com/ethereum/consensus-specs/blob/d70dcd9926a4bbe987f1b4e65c3e05bd029fcfb8/specs/altair/light-client/full-node.md#create_light_client_update
// def create_light_client_update(state: BeaconState,
//
// block: SignedBeaconBlock,
// attested_state: BeaconState,
// finalized_block: Optional[SignedBeaconBlock]) -> LightClientUpdate:
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
// assert sum(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS
//
// assert state.slot == state.latest_block_header.slot
// header = state.latest_block_header.copy()
// header.state_root = hash_tree_root(state)
// assert hash_tree_root(header) == hash_tree_root(block.message)
// update_signature_period = compute_sync_committee_period(compute_epoch_at_slot(block.message.slot))
//
// assert attested_state.slot == attested_state.latest_block_header.slot
// attested_header = attested_state.latest_block_header.copy()
// attested_header.state_root = hash_tree_root(attested_state)
// assert hash_tree_root(attested_header) == block.message.parent_root
// update_attested_period = compute_sync_committee_period(compute_epoch_at_slot(attested_header.slot))
//
// # `next_sync_committee` is only useful if the message is signed by the current sync committee
// if update_attested_period == update_signature_period:
// next_sync_committee = attested_state.next_sync_committee
// next_sync_committee_branch = compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX)
// else:
// next_sync_committee = SyncCommittee()
// next_sync_committee_branch = [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]
//
// # Indicate finality whenever possible
// if finalized_block is not None:
// if finalized_block.message.slot != GENESIS_SLOT:
// finalized_header = BeaconBlockHeader(
// slot=finalized_block.message.slot,
// proposer_index=finalized_block.message.proposer_index,
// parent_root=finalized_block.message.parent_root,
// state_root=finalized_block.message.state_root,
// body_root=hash_tree_root(finalized_block.message.body),
// )
// assert hash_tree_root(finalized_header) == attested_state.finalized_checkpoint.root
// else:
// assert attested_state.finalized_checkpoint.root == Bytes32()
// finalized_header = BeaconBlockHeader()
// finality_branch = compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX)
// else:
// finalized_header = BeaconBlockHeader()
// finality_branch = [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))]
//
// return LightClientUpdate(
// attested_header=attested_header,
// next_sync_committee=next_sync_committee,
// next_sync_committee_branch=next_sync_committee_branch,
// finalized_header=finalized_header,
// finality_branch=finality_branch,
// sync_aggregate=block.message.body.sync_aggregate,
// signature_slot=block.message.slot,
// )
func NewLightClientUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) {
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
attestedEpoch := slots.ToEpoch(attestedState.Slot())
if attestedEpoch < params.BeaconConfig().AltairForkEpoch {
@@ -85,7 +172,6 @@ func NewLightClientOptimisticUpdateFromBeaconState(
if err != nil {
return nil, errors.Wrap(err, "could not get sync aggregate")
}
if syncAggregate.SyncCommitteeBits.Count() < params.BeaconConfig().MinSyncCommitteeParticipants {
return nil, fmt.Errorf("invalid sync committee bits count %d", syncAggregate.SyncCommitteeBits.Count())
}
@@ -102,21 +188,21 @@ func NewLightClientOptimisticUpdateFromBeaconState(
return nil, errors.Wrap(err, "could not get state root")
}
header.StateRoot = stateRoot[:]
headerRoot, err := header.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get header root")
}
blockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if headerRoot != blockRoot {
return nil, fmt.Errorf("header root %#x not equal to block root %#x", headerRoot, blockRoot)
}
// update_signature_period = compute_sync_committee_period(compute_epoch_at_slot(block.message.slot))
updateSignaturePeriod := slots.SyncCommitteePeriod(slots.ToEpoch(block.Block().Slot()))
// assert attested_state.slot == attested_state.latest_block_header.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)
@@ -137,34 +223,32 @@ func NewLightClientOptimisticUpdateFromBeaconState(
if err != nil {
return nil, errors.Wrap(err, "could not get attested header root")
}
if attestedHeaderRoot != block.Block().ParentRoot() {
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x", attestedHeaderRoot, block.Block().ParentRoot())
}
syncAggregateResult := &ethpbv1.SyncAggregate{
SyncCommitteeBits: syncAggregate.SyncCommitteeBits,
SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature,
// update_attested_period = compute_sync_committee_period(compute_epoch_at_slot(attested_header.slot))
updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(attestedHeader.Slot))
// update = LightClientUpdate()
result, err := createDefaultLightClientUpdate(block.Block().Version())
if err != nil {
return nil, errors.Wrap(err, "could not create default light client update")
}
result := &ethpbv2.LightClientUpdate{
SyncAggregate: syncAggregateResult,
SignatureSlot: block.Block().Slot(),
// update.attested_header = block_to_light_client_header(attested_block)
blockHeader := &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
},
},
HeaderAltair: &ethpbv2.LightClientHeader{Beacon: blockHeader},
},
}
case version.Capella:
@@ -172,49 +256,32 @@ func NewLightClientOptimisticUpdateFromBeaconState(
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
},
Beacon: blockHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
case version.Deneb, version.Electra:
case version.Deneb:
executionPayloadHeader, err := getExecutionPayloadHeaderDeneb(block)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
},
Beacon: blockHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
@@ -224,168 +291,198 @@ func NewLightClientOptimisticUpdateFromBeaconState(
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
}
return result, nil
}
// if update_attested_period == update_signature_period
if updateAttestedPeriod == updateSignaturePeriod {
tempNextSyncCommittee, err := attestedState.NextSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee")
}
nextSyncCommittee := &ethpbv2.SyncCommittee{
Pubkeys: tempNextSyncCommittee.Pubkeys,
AggregatePubkey: tempNextSyncCommittee.AggregatePubkey,
}
nextSyncCommitteeBranch, err := attestedState.NextSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee proof")
}
func NewLightClientFinalityUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) {
result, err := NewLightClientOptimisticUpdateFromBeaconState(
ctx,
state,
block,
attestedState,
)
if err != nil {
return nil, err
// update.next_sync_committee = attested_state.next_sync_committee
result.NextSyncCommittee = nextSyncCommittee
// update.next_sync_committee_branch = NextSyncCommitteeBranch(
// compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot)))
result.NextSyncCommitteeBranch = nextSyncCommitteeBranch
}
// Indicate finality whenever possible
var finalizedHeaderBeacon *ethpbv1.BeaconBlockHeader
var finalityBranch [][]byte
// if finalized_block is not None
if finalizedBlock != nil && !finalizedBlock.IsNil() {
// if finalized_block.message.slot != GENESIS_SLOT
if finalizedBlock.Block().Slot() != 0 {
tempFinalizedHeader, err := finalizedBlock.Header()
// update.finalized_header = block_to_light_client_header(finalized_block)
v1alpha1FinalizedHeader, err := finalizedBlock.Header()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header")
}
finalizedHeaderBeacon := migration.V1Alpha1SignedHeaderToV1(tempFinalizedHeader).GetMessage()
finalizedHeaderRoot, err := finalizedHeaderBeacon.HashTreeRoot()
finalizedHeader := migration.V1Alpha1SignedHeaderToV1(v1alpha1FinalizedHeader).GetMessage()
finalizedHeaderRoot, err := finalizedHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header root")
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{Beacon: finalizedHeader},
},
}
case version.Capella:
executionPayloadHeader, err := getExecutionPayloadHeaderCapella(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, finalizedBlock.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
case version.Deneb:
executionPayloadHeader, err := getExecutionPayloadHeaderDeneb(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, finalizedBlock.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
}
// assert hash_tree_root(update.finalized_header.beacon) == attested_state.finalized_checkpoint.root
if finalizedHeaderRoot != bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root) {
return nil, fmt.Errorf("finalized header root %#x not equal to attested finalized checkpoint root %#x", finalizedHeaderRoot, bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root))
return nil, fmt.Errorf(
"finalized header root %#x not equal to attested finalized checkpoint root %#x",
finalizedHeaderRoot,
bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root),
)
}
} else {
// assert attested_state.finalized_checkpoint.root == Bytes32()
if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) {
return nil, fmt.Errorf("invalid finalized header root %v", attestedState.FinalizedCheckpoint().Root)
}
finalizedHeaderBeacon = &ethpbv1.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
}
}
var bErr error
finalityBranch, bErr = attestedState.FinalizedRootProof(ctx)
if bErr != nil {
return nil, errors.Wrap(bErr, "could not get finalized root proof")
}
} else {
finalizedHeaderBeacon = &ethpbv1.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
}
finalityBranch = make([][]byte, FinalityBranchNumOfLeaves)
for i := 0; i < FinalityBranchNumOfLeaves; i++ {
finalityBranch[i] = make([]byte, 32)
}
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{Beacon: finalizedHeaderBeacon},
},
// update.finality_branch = FinalityBranch(
// compute_merkle_proof(attested_state, finalized_root_gindex_at_slot(attested_state.slot)))
finalityBranch, err := attestedState.FinalizedRootProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get finalized root proof")
}
result.FinalityBranch = finalityBranch
case version.Capella:
if finalizedBlock != nil && !finalizedBlock.IsNil() {
execution, err := getExecutionPayloadHeaderCapella(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionBranch, err := blocks.PayloadProof(ctx, finalizedBlock.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
} else {
execution := createEmptyExecutionPayloadHeaderCapella()
executionBranch := make([][]byte, 0)
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
}
case version.Deneb, version.Electra:
if finalizedBlock != nil && !finalizedBlock.IsNil() {
execution, err := getExecutionPayloadHeaderDeneb(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionBranch, err := blocks.PayloadProof(ctx, finalizedBlock.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
} else {
execution := createEmptyExecutionPayloadHeaderDeneb()
executionBranch := make([][]byte, 0)
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
}
// update.sync_aggregate = block.message.body.sync_aggregate
result.SyncAggregate = &ethpbv1.SyncAggregate{
SyncCommitteeBits: syncAggregate.SyncCommitteeBits,
SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature,
}
// update.signature_slot = block.message.slot
result.SignatureSlot = block.Block().Slot()
return result, nil
}
func createDefaultLightClientUpdate(v int) (*ethpbv2.LightClientUpdate, error) {
syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize
pubKeys := make([][]byte, syncCommitteeSize)
for i := uint64(0); i < syncCommitteeSize; i++ {
pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength)
}
nextSyncCommittee := &ethpbv2.SyncCommittee{
Pubkeys: pubKeys,
AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength),
}
nextSyncCommitteeBranch := make([][]byte, fieldparams.NextSyncCommitteeBranchDepth)
for i := 0; i < fieldparams.NextSyncCommitteeBranchDepth; i++ {
nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength)
}
executionBranch := make([][]byte, executionBranchNumOfLeaves)
for i := 0; i < executionBranchNumOfLeaves; i++ {
executionBranch[i] = make([]byte, 32)
}
finalizedBlockHeader := &ethpbv1.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
}
finalityBranch := make([][]byte, FinalityBranchNumOfLeaves)
for i := 0; i < FinalityBranchNumOfLeaves; i++ {
finalityBranch[i] = make([]byte, 32)
}
var finalizedHeader *ethpbv2.LightClientHeaderContainer
switch v {
case version.Altair, version.Bellatrix:
finalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{
Beacon: finalizedBlockHeader,
},
},
}
case version.Capella:
finalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedBlockHeader,
Execution: createEmptyExecutionPayloadHeaderCapella(),
ExecutionBranch: executionBranch,
},
},
}
case version.Deneb:
finalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedBlockHeader,
Execution: createEmptyExecutionPayloadHeaderDeneb(),
ExecutionBranch: executionBranch,
},
},
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(v))
}
return &ethpbv2.LightClientUpdate{
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalizedHeader: finalizedHeader,
FinalityBranch: finalityBranch,
}, nil
}
func createEmptyExecutionPayloadHeaderCapella() *enginev1.ExecutionPayloadHeaderCapella {
return &enginev1.ExecutionPayloadHeaderCapella{
ParentHash: make([]byte, 32),
@@ -535,23 +632,6 @@ func getExecutionPayloadHeaderDeneb(block interfaces.ReadOnlySignedBeaconBlock)
return execution, nil
}
func NewLightClientUpdateFromFinalityUpdate(update *ethpbv2.LightClientFinalityUpdate) *ethpbv2.LightClientUpdate {
return &ethpbv2.LightClientUpdate{
AttestedHeader: update.AttestedHeader,
FinalizedHeader: update.FinalizedHeader,
FinalityBranch: update.FinalityBranch,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
}
func NewLightClientUpdateFromOptimisticUpdate(update *ethpbv2.LightClientOptimisticUpdate) *ethpbv2.LightClientUpdate {
return &ethpbv2.LightClientUpdate{
AttestedHeader: update.AttestedHeader,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
}
func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) {
transactionsRoot, err := payload.TransactionsRoot()
@@ -590,6 +670,10 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
}
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()
stateRoot := block.Block().StateRoot()
bodyRoot, err := block.Block().Body().HashTreeRoot()
@@ -610,7 +694,7 @@ func BlockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock)
func BlockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderCapella, error) {
if block.Version() != version.Capella {
return nil, fmt.Errorf("creating Capella light client header is not supported before Capella, invalid slot %d", block.Block().Slot())
return nil, fmt.Errorf("block version is %s instead of Capella", version.String(block.Version()))
}
payload, err := block.Block().Body().Execution()
@@ -671,9 +755,8 @@ func BlockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadO
}
func BlockToLightClientHeaderDeneb(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderDeneb, error) {
epoch := slots.ToEpoch(block.Block().Slot())
if epoch < params.BeaconConfig().DenebForkEpoch {
return nil, fmt.Errorf("creating Deneb light client header is not supported before Deneb, invalid slot %d", block.Block().Slot())
if block.Version() != version.Deneb {
return nil, fmt.Errorf("block version is %s instead of Deneb", version.String(block.Version()))
}
payload, err := block.Block().Body().Execution()

View File

@@ -10,27 +10,10 @@ import (
light_client "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateCapella(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
require.Equal(t, (*v2.LightClientHeaderContainer)(nil), update.FinalizedHeader, "Finalized header is not nil")
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
}
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateAltair(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
@@ -40,11 +23,21 @@ func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateAltair(t *test
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
}
require.Equal(t, (*v2.LightClientHeaderContainer)(nil), update.FinalizedHeader, "Finalized header is not nil")
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateCapella(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
}
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateDeneb(t *testing.T) {
@@ -56,22 +49,21 @@ func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateDeneb(t *testi
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
require.Equal(t, (*v2.LightClientHeaderContainer)(nil), update.FinalizedHeader, "Finalized header is not nil")
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateCapella(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateAltair(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, nil)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
@@ -88,17 +80,16 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateCapella(t *testi
}
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateAltair(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateCapella(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, nil)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
@@ -124,8 +115,8 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateDeneb(t *testing
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")

View File

@@ -301,45 +301,15 @@ func (s *Server) handleStateEvents(ctx context.Context, w http.ResponseWriter, f
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, LightClientFinalityUpdateTopic)
}
var finalityBranch []string
for _, b := range updateData.Data.FinalityBranch {
finalityBranch = append(finalityBranch, hexutil.Encode(b))
}
attestedBeacon, err := updateData.Data.AttestedHeader.GetBeacon()
update, err := structs.LightClientFinalityUpdateFromConsensus(updateData.Data)
if err != nil {
return errors.Wrap(err, "could not get attested header")
return err
}
finalizedBeacon, err := updateData.Data.FinalizedHeader.GetBeacon()
if err != nil {
return errors.Wrap(err, "could not get finalized header")
}
update := &structs.LightClientFinalityUpdateEvent{
updateEvent := &structs.LightClientFinalityUpdateEvent{
Version: version.String(int(updateData.Version)),
Data: &structs.LightClientFinalityUpdate{
AttestedHeader: &structs.BeaconBlockHeader{
Slot: fmt.Sprintf("%d", attestedBeacon.Slot),
ProposerIndex: fmt.Sprintf("%d", attestedBeacon.ProposerIndex),
ParentRoot: hexutil.Encode(attestedBeacon.ParentRoot),
StateRoot: hexutil.Encode(attestedBeacon.StateRoot),
BodyRoot: hexutil.Encode(attestedBeacon.BodyRoot),
},
FinalizedHeader: &structs.BeaconBlockHeader{
Slot: fmt.Sprintf("%d", finalizedBeacon.Slot),
ProposerIndex: fmt.Sprintf("%d", finalizedBeacon.ProposerIndex),
ParentRoot: hexutil.Encode(finalizedBeacon.ParentRoot),
StateRoot: hexutil.Encode(finalizedBeacon.StateRoot),
},
FinalityBranch: finalityBranch,
SyncAggregate: &structs.SyncAggregate{
SyncCommitteeBits: hexutil.Encode(updateData.Data.SyncAggregate.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(updateData.Data.SyncAggregate.SyncCommitteeSignature),
},
SignatureSlot: fmt.Sprintf("%d", updateData.Data.SignatureSlot),
},
Data: update,
}
return send(w, flusher, LightClientFinalityUpdateTopic, update)
return send(w, flusher, LightClientFinalityUpdateTopic, updateEvent)
case statefeed.LightClientOptimisticUpdate:
if _, ok := requestedTopics[LightClientOptimisticUpdateTopic]; !ok {
return nil
@@ -348,28 +318,15 @@ func (s *Server) handleStateEvents(ctx context.Context, w http.ResponseWriter, f
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, LightClientOptimisticUpdateTopic)
}
attestedBeacon, err := updateData.Data.AttestedHeader.GetBeacon()
update, err := structs.LightClientOptimisticUpdateFromConsensus(updateData.Data)
if err != nil {
return errors.Wrap(err, "could not get attested header")
return err
}
update := &structs.LightClientOptimisticUpdateEvent{
updateEvent := &structs.LightClientOptimisticUpdateEvent{
Version: version.String(int(updateData.Version)),
Data: &structs.LightClientOptimisticUpdate{
AttestedHeader: &structs.BeaconBlockHeader{
Slot: fmt.Sprintf("%d", attestedBeacon.Slot),
ProposerIndex: fmt.Sprintf("%d", attestedBeacon.ProposerIndex),
ParentRoot: hexutil.Encode(attestedBeacon.ParentRoot),
StateRoot: hexutil.Encode(attestedBeacon.StateRoot),
BodyRoot: hexutil.Encode(attestedBeacon.BodyRoot),
},
SyncAggregate: &structs.SyncAggregate{
SyncCommitteeBits: hexutil.Encode(updateData.Data.SyncAggregate.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(updateData.Data.SyncAggregate.SyncCommitteeSignature),
},
SignatureSlot: fmt.Sprintf("%d", updateData.Data.SignatureSlot),
},
Data: update,
}
return send(w, flusher, LightClientOptimisticUpdateTopic, update)
return send(w, flusher, LightClientOptimisticUpdateTopic, updateEvent)
case statefeed.Reorg:
if _, ok := requestedTopics[ChainReorgTopic]; !ok {
return nil

View File

@@ -27,9 +27,7 @@ go_library(
"//encoding/ssz:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",

View File

@@ -118,7 +118,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
}
// Populate updates
var updates []*structs.LightClientUpdateWithVersion
var updates []*structs.LightClientUpdateResponse
for period := startPeriod; period <= endPeriod; period++ {
// Get the last known state of the period,
// 1. We wish the block has a parent in the same period if possible
@@ -199,7 +199,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
}
}
update, err := createLightClientUpdate(
update, err := newLightClientUpdateFromBeaconState(
ctx,
state,
block,
@@ -208,7 +208,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
)
if err == nil {
updates = append(updates, &structs.LightClientUpdateWithVersion{
updates = append(updates, &structs.LightClientUpdateResponse{
Version: version.String(attestedState.Version()),
Data: update,
})
@@ -225,7 +225,6 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
// GetLightClientFinalityUpdate - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/finality_update.yaml
func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.Request) {
// Prepare
ctx, span := trace.StartSpan(req.Context(), "beacon.GetLightClientFinalityUpdate")
defer span.End()
@@ -233,56 +232,48 @@ func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.R
minSyncCommitteeParticipants := float64(params.BeaconConfig().MinSyncCommitteeParticipants)
minSignatures := uint64(math.Ceil(minSyncCommitteeParticipants * 2 / 3))
block, err := s.getLightClientEventBlock(ctx, minSignatures)
block, err := s.suitableBlock(ctx, minSignatures)
if !shared.WriteBlockFetchError(w, block, err) {
return
}
state, err := s.Stater.StateBySlot(ctx, block.Block().Slot())
st, err := s.Stater.StateBySlot(ctx, block.Block().Slot())
if err != nil {
httputil.HandleError(w, "could not get state: "+err.Error(), http.StatusInternalServerError)
httputil.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
return
}
// Get attested state
attestedRoot := block.Block().ParentRoot()
attestedBlock, err := s.Blocker.Block(ctx, attestedRoot[:])
if err != nil || attestedBlock == nil {
httputil.HandleError(w, "could not get attested block: "+err.Error(), http.StatusInternalServerError)
if !shared.WriteBlockFetchError(w, block, errors.Wrap(err, "could not get attested block")) {
return
}
attestedSlot := attestedBlock.Block().Slot()
attestedState, err := s.Stater.StateBySlot(ctx, attestedSlot)
if err != nil {
httputil.HandleError(w, "could not get attested state: "+err.Error(), http.StatusInternalServerError)
httputil.HandleError(w, "Could not get attested state: "+err.Error(), http.StatusInternalServerError)
return
}
// 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
}
finalizedCheckpoint := attestedState.FinalizedCheckpoint()
if finalizedCheckpoint == nil {
httputil.HandleError(w, "Attested state does not have a finalized checkpoint", http.StatusInternalServerError)
return
}
update, err := newLightClientFinalityUpdateFromBeaconState(
ctx,
state,
block,
attestedState,
finalizedBlock,
)
if err != nil {
httputil.HandleError(w, "could not get light client finality update: "+err.Error(), http.StatusInternalServerError)
finalizedRoot := bytesutil.ToBytes32(finalizedCheckpoint.Root)
finalizedBlock, err = s.Blocker.Block(ctx, finalizedRoot[:])
if !shared.WriteBlockFetchError(w, block, errors.Wrap(err, "could not get finalized block")) {
return
}
response := &structs.LightClientUpdateWithVersion{
update, err := newLightClientFinalityUpdateFromBeaconState(ctx, st, block, attestedState, finalizedBlock)
if err != nil {
httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError)
return
}
response := &structs.LightClientFinalityUpdateResponse{
Version: version.String(attestedState.Version()),
Data: update,
}
@@ -292,54 +283,42 @@ func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.R
// GetLightClientOptimisticUpdate - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/optimistic_update.yaml
func (s *Server) GetLightClientOptimisticUpdate(w http.ResponseWriter, req *http.Request) {
// Prepare
ctx, span := trace.StartSpan(req.Context(), "beacon.GetLightClientOptimisticUpdate")
defer span.End()
minSignatures := params.BeaconConfig().MinSyncCommitteeParticipants
block, err := s.getLightClientEventBlock(ctx, minSignatures)
block, err := s.suitableBlock(ctx, params.BeaconConfig().MinSyncCommitteeParticipants)
if !shared.WriteBlockFetchError(w, block, err) {
return
}
state, err := s.Stater.StateBySlot(ctx, block.Block().Slot())
st, err := s.Stater.StateBySlot(ctx, block.Block().Slot())
if err != nil {
httputil.HandleError(w, "could not get state: "+err.Error(), http.StatusInternalServerError)
return
}
// Get attested state
attestedRoot := block.Block().ParentRoot()
attestedBlock, err := s.Blocker.Block(ctx, attestedRoot[:])
if err != nil {
httputil.HandleError(w, "could not get attested block: "+err.Error(), http.StatusInternalServerError)
httputil.HandleError(w, "Could not get attested block: "+err.Error(), http.StatusInternalServerError)
return
}
if attestedBlock == nil {
httputil.HandleError(w, "attested block is nil", http.StatusInternalServerError)
httputil.HandleError(w, "Attested block is nil", http.StatusInternalServerError)
return
}
attestedSlot := attestedBlock.Block().Slot()
attestedState, err := s.Stater.StateBySlot(ctx, attestedSlot)
if err != nil {
httputil.HandleError(w, "could not get attested state: "+err.Error(), http.StatusInternalServerError)
httputil.HandleError(w, "Could not get attested state: "+err.Error(), http.StatusInternalServerError)
return
}
update, err := newLightClientOptimisticUpdateFromBeaconState(
ctx,
state,
block,
attestedState,
)
update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, st, block, attestedState)
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
}
response := &structs.LightClientUpdateWithVersion{
response := &structs.LightClientOptimisticUpdateResponse{
Version: version.String(attestedState.Version()),
Data: update,
}
@@ -347,17 +326,15 @@ func (s *Server) GetLightClientOptimisticUpdate(w http.ResponseWriter, req *http
httputil.WriteJson(w, response)
}
// getLightClientEventBlock - returns the block that should be used for light client events, which satisfies the minimum number of signatures from sync committee
func (s *Server) getLightClientEventBlock(ctx context.Context, minSignaturesRequired uint64) (interfaces.ReadOnlySignedBeaconBlock, error) {
// Get the current state
state, err := s.HeadFetcher.HeadState(ctx)
// suitableBlock returns the latest block that satisfies all criteria required for creating a new update
func (s *Server) suitableBlock(ctx context.Context, minSignaturesRequired uint64) (interfaces.ReadOnlySignedBeaconBlock, error) {
st, err := s.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get head state")
}
// Get the block
latestBlockHeader := *state.LatestBlockHeader()
stateRoot, err := state.HashTreeRoot(ctx)
latestBlockHeader := st.LatestBlockHeader()
stateRoot, err := st.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
@@ -377,7 +354,7 @@ func (s *Server) getLightClientEventBlock(ctx context.Context, minSignaturesRequ
// Loop through the blocks until we find a block that satisfies minSignaturesRequired requirement
var numOfSyncCommitteeSignatures uint64
if syncAggregate, err := block.Block().Body().SyncAggregate(); err == nil && syncAggregate != nil {
if syncAggregate, err := block.Block().Body().SyncAggregate(); err == nil {
numOfSyncCommitteeSignatures = syncAggregate.SyncCommitteeBits.Count()
}
@@ -394,7 +371,7 @@ func (s *Server) getLightClientEventBlock(ctx context.Context, minSignaturesRequ
// Get the number of sync committee signatures
numOfSyncCommitteeSignatures = 0
if syncAggregate, err := block.Block().Body().SyncAggregate(); err == nil && syncAggregate != nil {
if syncAggregate, err := block.Block().Body().SyncAggregate(); err == nil {
numOfSyncCommitteeSignatures = syncAggregate.SyncCommitteeBits.Count()
}
}

View File

@@ -1235,7 +1235,7 @@ func TestLightClientHandler_GetLightClientFinalityUpdateAltair(t *testing.T) {
s.GetLightClientFinalityUpdate(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientUpdateWithVersion
var resp *structs.LightClientUpdateResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeader
@@ -1345,7 +1345,7 @@ func TestLightClientHandler_GetLightClientFinalityUpdateCapella(t *testing.T) {
s.GetLightClientFinalityUpdate(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientUpdateWithVersion
var resp *structs.LightClientUpdateResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeader
@@ -1455,7 +1455,7 @@ func TestLightClientHandler_GetLightClientFinalityUpdateDeneb(t *testing.T) {
s.GetLightClientFinalityUpdate(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientUpdateWithVersion
var resp *structs.LightClientUpdateResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeaderDeneb
@@ -1565,7 +1565,7 @@ func TestLightClientHandler_GetLightClientOptimisticUpdateAltair(t *testing.T) {
s.GetLightClientOptimisticUpdate(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientUpdateWithVersion
var resp *structs.LightClientUpdateResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeader
@@ -1675,7 +1675,7 @@ func TestLightClientHandler_GetLightClientOptimisticUpdateCapella(t *testing.T)
s.GetLightClientOptimisticUpdate(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientUpdateWithVersion
var resp *structs.LightClientUpdateResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeaderCapella
@@ -1785,7 +1785,7 @@ func TestLightClientHandler_GetLightClientOptimisticUpdateDeneb(t *testing.T) {
s.GetLightClientOptimisticUpdate(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientUpdateWithVersion
var resp *structs.LightClientUpdateResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeaderDeneb
@@ -1890,7 +1890,7 @@ func TestLightClientHandler_GetLightClientEventBlock(t *testing.T) {
}
minSignaturesRequired := uint64(100)
eventBlock, err := s.getLightClientEventBlock(ctx, minSignaturesRequired)
eventBlock, err := s.suitableBlock(ctx, minSignaturesRequired)
require.NoError(t, err)
require.NotNil(t, eventBlock)
@@ -1997,7 +1997,7 @@ func TestLightClientHandler_GetLightClientEventBlock_NeedFetchParent(t *testing.
}
minSignaturesRequired := uint64(100)
eventBlock, err := s.getLightClientEventBlock(ctx, minSignaturesRequired)
eventBlock, err := s.suitableBlock(ctx, minSignaturesRequired)
require.NoError(t, err)
require.NotNil(t, eventBlock)

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"github.com/pkg/errors"
@@ -21,9 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/proto/migration"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
@@ -349,128 +346,19 @@ func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconStat
return result, nil
}
// createLightClientUpdate - implements https://github.
// com/ethereum/consensus-specs/blob/d70dcd9926a4bbe987f1b4e65c3e05bd029fcfb8/specs/altair/light-client/full-node.md#create_light_client_update
// def create_light_client_update(state: BeaconState,
//
// block: SignedBeaconBlock,
// attested_state: BeaconState,
// finalized_block: Optional[SignedBeaconBlock]) -> LightClientUpdate:
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
// assert sum(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS
//
// assert state.slot == state.latest_block_header.slot
// header = state.latest_block_header.copy()
// header.state_root = hash_tree_root(state)
// assert hash_tree_root(header) == hash_tree_root(block.message)
// update_signature_period = compute_sync_committee_period(compute_epoch_at_slot(block.message.slot))
//
// assert attested_state.slot == attested_state.latest_block_header.slot
// attested_header = attested_state.latest_block_header.copy()
// attested_header.state_root = hash_tree_root(attested_state)
// assert hash_tree_root(attested_header) == block.message.parent_root
// update_attested_period = compute_sync_committee_period(compute_epoch_at_slot(attested_header.slot))
//
// # `next_sync_committee` is only useful if the message is signed by the current sync committee
// if update_attested_period == update_signature_period:
// next_sync_committee = attested_state.next_sync_committee
// next_sync_committee_branch = compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX)
// else:
// next_sync_committee = SyncCommittee()
// next_sync_committee_branch = [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]
//
// # Indicate finality whenever possible
// if finalized_block is not None:
// if finalized_block.message.slot != GENESIS_SLOT:
// finalized_header = BeaconBlockHeader(
// slot=finalized_block.message.slot,
// proposer_index=finalized_block.message.proposer_index,
// parent_root=finalized_block.message.parent_root,
// state_root=finalized_block.message.state_root,
// body_root=hash_tree_root(finalized_block.message.body),
// )
// assert hash_tree_root(finalized_header) == attested_state.finalized_checkpoint.root
// else:
// assert attested_state.finalized_checkpoint.root == Bytes32()
// finalized_header = BeaconBlockHeader()
// finality_branch = compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX)
// else:
// finalized_header = BeaconBlockHeader()
// finality_branch = [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))]
//
// return LightClientUpdate(
// attested_header=attested_header,
// next_sync_committee=next_sync_committee,
// next_sync_committee_branch=next_sync_committee_branch,
// finalized_header=finalized_header,
// finality_branch=finality_branch,
// sync_aggregate=block.message.body.sync_aggregate,
// signature_slot=block.message.slot,
// )
func createLightClientUpdate(
func newLightClientUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientUpdate, error) {
result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientUpdate, error) {
result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
if err != nil {
return nil, err
}
// Generate next sync committee and proof
var nextSyncCommittee *v2.SyncCommittee
var nextSyncCommitteeBranch [][]byte
// update_signature_period = compute_sync_committee_period(compute_epoch_at_slot(block.message.slot))
updateSignaturePeriod := slots.SyncCommitteePeriod(slots.ToEpoch(block.Block().Slot()))
// update_attested_period = compute_sync_committee_period(compute_epoch_at_slot(attested_header.slot))
resultAttestedHeaderBeacon, err := result.AttestedHeader.GetBeacon()
if err != nil {
return nil, errors.Wrap(err, "could not get attested header beacon")
}
updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(resultAttestedHeaderBeacon.Slot))
if updateAttestedPeriod == updateSignaturePeriod {
tempNextSyncCommittee, err := attestedState.NextSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee")
}
nextSyncCommittee = &v2.SyncCommittee{
Pubkeys: tempNextSyncCommittee.Pubkeys,
AggregatePubkey: tempNextSyncCommittee.AggregatePubkey,
}
nextSyncCommitteeBranch, err = attestedState.NextSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee proof")
}
} else {
syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize
pubKeys := make([][]byte, syncCommitteeSize)
for i := uint64(0); i < syncCommitteeSize; i++ {
pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength)
}
nextSyncCommittee = &v2.SyncCommittee{
Pubkeys: pubKeys,
AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength),
}
nextSyncCommitteeBranch = make([][]byte, fieldparams.NextSyncCommitteeBranchDepth)
for i := 0; i < fieldparams.NextSyncCommitteeBranchDepth; i++ {
nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength)
}
}
result.NextSyncCommittee = nextSyncCommittee
result.NextSyncCommitteeBranch = nextSyncCommitteeBranch
res, err := newLightClientUpdateToJSON(result)
if err != nil {
return nil, errors.Wrap(err, "could not convert light client update to JSON")
}
return res, nil
return structs.LightClientUpdateFromConsensus(result)
}
func newLightClientFinalityUpdateFromBeaconState(
@@ -478,99 +366,28 @@ func newLightClientFinalityUpdateFromBeaconState(
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientUpdate, error) {
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientFinalityUpdate, error) {
result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
if err != nil {
return nil, err
}
res, err := newLightClientUpdateToJSON(result)
if err != nil {
return nil, errors.Wrap(err, "could not convert light client update to JSON")
}
return res, nil
return structs.LightClientFinalityUpdateFromConsensus(result)
}
func newLightClientOptimisticUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState) (*structs.LightClientUpdate, error) {
attestedState state.BeaconState,
) (*structs.LightClientOptimisticUpdate, error) {
result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, state, block, attestedState)
if err != nil {
return nil, err
}
res, err := newLightClientUpdateToJSON(result)
if err != nil {
return nil, errors.Wrap(err, "could not convert light client update to JSON")
}
return res, nil
}
func branchToJSON(branchBytes [][]byte) []string {
if branchBytes == nil {
return nil
}
branch := make([]string, len(branchBytes))
for i, root := range branchBytes {
branch[i] = hexutil.Encode(root)
}
return branch
}
func syncAggregateToJSON(input *v1.SyncAggregate) *structs.SyncAggregate {
if input == nil {
return nil
}
return &structs.SyncAggregate{
SyncCommitteeBits: hexutil.Encode(input.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(input.SyncCommitteeSignature),
}
}
func newLightClientUpdateToJSON(input *v2.LightClientUpdate) (*structs.LightClientUpdate, error) {
if input == nil {
return nil, errors.New("input is nil")
}
var nextSyncCommittee *structs.SyncCommittee
if input.NextSyncCommittee != nil {
nextSyncCommittee = structs.SyncCommitteeFromConsensus(migration.V2SyncCommitteeToV1Alpha1(input.NextSyncCommittee))
}
var finalizedHeader *structs.BeaconBlockHeader
if input.FinalizedHeader != nil {
inputFinalizedHeaderBeacon, err := input.FinalizedHeader.GetBeacon()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header beacon")
}
finalizedHeader = structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(inputFinalizedHeaderBeacon))
}
inputAttestedHeaderBeacon, err := input.AttestedHeader.GetBeacon()
if err != nil {
return nil, errors.Wrap(err, "could not get attested header beacon")
}
attestedHeaderJson, err := json.Marshal(&structs.LightClientHeader{Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(inputAttestedHeaderBeacon))})
if err != nil {
return nil, errors.Wrap(err, "could not convert attested header to raw message")
}
finalizedHeaderJson, err := json.Marshal(&structs.LightClientHeader{Beacon: finalizedHeader})
if err != nil {
return nil, errors.Wrap(err, "could not convert finalized header to raw message")
}
result := &structs.LightClientUpdate{
AttestedHeader: attestedHeaderJson,
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: branchToJSON(input.NextSyncCommitteeBranch),
FinalizedHeader: finalizedHeaderJson,
FinalityBranch: branchToJSON(input.FinalityBranch),
SyncAggregate: syncAggregateToJSON(input.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(input.SignatureSlot), 10),
}
return result, nil
return structs.LightClientOptimisticUpdateFromConsensus(result)
}
func IsSyncCommitteeUpdate(update *v2.LightClientUpdate) bool {

View File

@@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
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"
"github.com/prysmaticlabs/prysm/v5/testing/require"
@@ -295,8 +296,8 @@ func (l *TestLightClient) SetupTestDeneb(blinded bool) *TestLightClient {
return l
}
func (l *TestLightClient) CheckAttestedHeader(update *ethpbv2.LightClientUpdate) {
updateAttestedHeaderBeacon, err := update.AttestedHeader.GetBeacon()
func (l *TestLightClient) CheckAttestedHeader(container *ethpbv2.LightClientHeaderContainer) {
updateAttestedHeaderBeacon, err := container.GetBeacon()
require.NoError(l.T, err)
require.Equal(l.T, l.AttestedHeader.Slot, updateAttestedHeaderBeacon.Slot, "Attested header slot is not equal")
require.Equal(l.T, l.AttestedHeader.ProposerIndex, updateAttestedHeaderBeacon.ProposerIndex, "Attested header proposer index is not equal")
@@ -308,9 +309,9 @@ func (l *TestLightClient) CheckAttestedHeader(update *ethpbv2.LightClientUpdate)
require.DeepSSZEqual(l.T, attestedStateRoot[:], updateAttestedHeaderBeacon.StateRoot, "Attested header state root is not equal")
}
func (l *TestLightClient) CheckSyncAggregate(update *ethpbv2.LightClientUpdate) {
func (l *TestLightClient) CheckSyncAggregate(sa *ethpbv1.SyncAggregate) {
syncAggregate, err := l.Block.Block().Body().SyncAggregate()
require.NoError(l.T, err)
require.DeepSSZEqual(l.T, syncAggregate.SyncCommitteeBits, update.SyncAggregate.SyncCommitteeBits, "SyncAggregate bits is not equal")
require.DeepSSZEqual(l.T, syncAggregate.SyncCommitteeSignature, update.SyncAggregate.SyncCommitteeSignature, "SyncAggregate signature is not equal")
require.DeepSSZEqual(l.T, syncAggregate.SyncCommitteeBits, sa.SyncCommitteeBits, "SyncAggregate bits is not equal")
require.DeepSSZEqual(l.T, syncAggregate.SyncCommitteeSignature, sa.SyncCommitteeSignature, "SyncAggregate signature is not equal")
}