diff --git a/CHANGELOG.md b/CHANGELOG.md index 0184b8e22988..b99fcea6ee45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/api/server/structs/BUILD.bazel b/api/server/structs/BUILD.bazel index cbe01272a175..f700ecb3cd04 100644 --- a/api/server/structs/BUILD.bazel +++ b/api/server/structs/BUILD.bazel @@ -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", diff --git a/api/server/structs/conversions_lightclient.go b/api/server/structs/conversions_lightclient.go index aa780a37ac30..83483bb53225 100644 --- a/api/server/structs/conversions_lightclient.go +++ b/api/server/structs/conversions_lightclient.go @@ -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) +} diff --git a/api/server/structs/endpoints_events.go b/api/server/structs/endpoints_events.go index 5b6d30cf3f6b..275a94580383 100644 --- a/api/server/structs/endpoints_events.go +++ b/api/server/structs/endpoints_events.go @@ -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"` -} diff --git a/api/server/structs/endpoints_lightclient.go b/api/server/structs/endpoints_lightclient.go index 0abf361c44f0..197f0b019fee 100644 --- a/api/server/structs/endpoints_lightclient.go +++ b/api/server/structs/endpoints_lightclient.go @@ -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 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 []*LightClientUpdateWithVersion `json:"updates"` + Updates []*LightClientUpdateResponse `json:"updates"` } diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 19410068a36d..63bde32770b1 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -193,7 +193,7 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte // Return the result result := ðpbv2.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 := ðpbv2.LightClientOptimisticUpdateWithVersion{ Version: ethpbv2.Version(signed.Version()), - Data: lightclient.CreateLightClientOptimisticUpdate(update), + Data: update, } return s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ diff --git a/beacon-chain/core/light-client/BUILD.bazel b/beacon-chain/core/light-client/BUILD.bazel index febad0829c55..9bde03319096 100644 --- a/beacon-chain/core/light-client/BUILD.bazel +++ b/beacon-chain/core/light-client/BUILD.bazel @@ -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", ], diff --git a/beacon-chain/core/light-client/lightclient.go b/beacon-chain/core/light-client/lightclient.go index d4d918a5f753..3953843b8df8 100644 --- a/beacon-chain/core/light-client/lightclient.go +++ b/beacon-chain/core/light-client/lightclient.go @@ -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 := ðpbv2.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 := ðpbv2.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 := ðpbv1.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)) - result := ðpbv2.LightClientUpdate{ - SyncAggregate: syncAggregateResult, - SignatureSlot: block.Block().Slot(), + // update = LightClientUpdate() + result, err := createDefaultLightClientUpdate(block.Block().Version()) + if err != nil { + return nil, errors.Wrap(err, "could not create default light client update") } + // update.attested_header = block_to_light_client_header(attested_block) + blockHeader := ðpbv1.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 = ðpbv2.LightClientHeaderContainer{ Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ - HeaderAltair: ðpbv2.LightClientHeader{ - Beacon: ðpbv1.BeaconBlockHeader{ - Slot: attestedHeader.Slot, - ProposerIndex: attestedHeader.ProposerIndex, - ParentRoot: attestedHeader.ParentRoot, - StateRoot: attestedHeader.StateRoot, - BodyRoot: attestedHeader.BodyRoot, - }, - }, + HeaderAltair: ðpbv2.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 = ðpbv2.LightClientHeaderContainer{ Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ HeaderCapella: ðpbv2.LightClientHeaderCapella{ - Beacon: ðpbv1.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 = ðpbv2.LightClientHeaderContainer{ Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ - Beacon: ðpbv1.BeaconBlockHeader{ - Slot: attestedHeader.Slot, - ProposerIndex: attestedHeader.ProposerIndex, - ParentRoot: attestedHeader.ParentRoot, - StateRoot: attestedHeader.StateRoot, - BodyRoot: attestedHeader.BodyRoot, - }, + Beacon: blockHeader, Execution: executionPayloadHeader, ExecutionBranch: executionPayloadProof, }, @@ -224,166 +291,196 @@ 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 := ðpbv2.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 - // Indicate finality whenever possible - var finalizedHeaderBeacon *ethpbv1.BeaconBlockHeader - var finalityBranch [][]byte + // update.next_sync_committee_branch = NextSyncCommitteeBranch( + // compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot))) + result.NextSyncCommitteeBranch = nextSyncCommitteeBranch + } + // 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 = ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.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 = ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.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 = ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.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 = ðpbv1.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 = ðpbv1.BeaconBlockHeader{ - Slot: 0, - ProposerIndex: 0, - ParentRoot: make([]byte, 32), - StateRoot: make([]byte, 32), - BodyRoot: make([]byte, 32), + // 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 + } - finalityBranch = make([][]byte, FinalityBranchNumOfLeaves) - for i := 0; i < FinalityBranchNumOfLeaves; i++ { - finalityBranch[i] = make([]byte, 32) - } + // update.sync_aggregate = block.message.body.sync_aggregate + result.SyncAggregate = ðpbv1.SyncAggregate{ + SyncCommitteeBits: syncAggregate.SyncCommitteeBits, + SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature, } - switch block.Block().Version() { + // 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 := ðpbv2.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 := ðpbv1.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: - result.FinalizedHeader = ðpbv2.LightClientHeaderContainer{ + finalizedHeader = ðpbv2.LightClientHeaderContainer{ Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ - HeaderAltair: ðpbv2.LightClientHeader{Beacon: finalizedHeaderBeacon}, + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: finalizedBlockHeader, + }, }, } - 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 = ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ - HeaderCapella: ðpbv2.LightClientHeaderCapella{ - Beacon: finalizedHeaderBeacon, - Execution: execution, - ExecutionBranch: executionBranch, - }, - }, - } - result.FinalityBranch = finalityBranch - } else { - execution := createEmptyExecutionPayloadHeaderCapella() - executionBranch := make([][]byte, 0) - - result.FinalizedHeader = ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ - HeaderCapella: ðpbv2.LightClientHeaderCapella{ - Beacon: finalizedHeaderBeacon, - Execution: execution, - ExecutionBranch: executionBranch, - }, + finalizedHeader = ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: finalizedBlockHeader, + Execution: createEmptyExecutionPayloadHeaderCapella(), + 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 = ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ - HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ - Beacon: finalizedHeaderBeacon, - Execution: execution, - ExecutionBranch: executionBranch, - }, - }, - } - result.FinalityBranch = finalityBranch - } else { - execution := createEmptyExecutionPayloadHeaderDeneb() - executionBranch := make([][]byte, 0) - - result.FinalizedHeader = ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ - HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ - Beacon: finalizedHeaderBeacon, - Execution: execution, - ExecutionBranch: executionBranch, - }, + case version.Deneb: + finalizedHeader = ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ + Beacon: finalizedBlockHeader, + Execution: createEmptyExecutionPayloadHeaderDeneb(), + ExecutionBranch: executionBranch, }, - } - - result.FinalityBranch = finalityBranch + }, } default: - return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version())) + return nil, fmt.Errorf("unsupported block version %s", version.String(v)) } - return result, nil + return ðpbv2.LightClientUpdate{ + NextSyncCommittee: nextSyncCommittee, + NextSyncCommitteeBranch: nextSyncCommitteeBranch, + FinalizedHeader: finalizedHeader, + FinalityBranch: finalityBranch, + }, nil } func createEmptyExecutionPayloadHeaderCapella() *enginev1.ExecutionPayloadHeaderCapella { @@ -535,23 +632,6 @@ func getExecutionPayloadHeaderDeneb(block interfaces.ReadOnlySignedBeaconBlock) return execution, nil } -func NewLightClientUpdateFromFinalityUpdate(update *ethpbv2.LightClientFinalityUpdate) *ethpbv2.LightClientUpdate { - return ðpbv2.LightClientUpdate{ - AttestedHeader: update.AttestedHeader, - FinalizedHeader: update.FinalizedHeader, - FinalityBranch: update.FinalityBranch, - SyncAggregate: update.SyncAggregate, - SignatureSlot: update.SignatureSlot, - } -} - -func NewLightClientUpdateFromOptimisticUpdate(update *ethpbv2.LightClientOptimisticUpdate) *ethpbv2.LightClientUpdate { - return ðpbv2.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() diff --git a/beacon-chain/core/light-client/lightclient_test.go b/beacon-chain/core/light-client/lightclient_test.go index de4a6902d907..513d3ff7beef 100644 --- a/beacon-chain/core/light-client/lightclient_test.go +++ b/beacon-chain/core/light-client/lightclient_test.go @@ -10,13 +10,12 @@ 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) +func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateAltair(t *testing.T) { + l := util.NewTestLightClient(t).SetupTestAltair() update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState) require.NoError(t, err) @@ -24,15 +23,12 @@ func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateCapella(t *tes 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_NewLightClientOptimisticUpdateFromBeaconStateAltair(t *testing.T) { - l := util.NewTestLightClient(t).SetupTestAltair() +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) @@ -40,11 +36,8 @@ 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) - - 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_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") diff --git a/beacon-chain/rpc/eth/events/events.go b/beacon-chain/rpc/eth/events/events.go index 980171cd9f2b..1c726be4591a 100644 --- a/beacon-chain/rpc/eth/events/events.go +++ b/beacon-chain/rpc/eth/events/events.go @@ -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), - }, - } - return send(w, flusher, LightClientFinalityUpdateTopic, update) + Data: 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), - }, - } - return send(w, flusher, LightClientOptimisticUpdateTopic, update) + Data: update, + } + return send(w, flusher, LightClientOptimisticUpdateTopic, updateEvent) case statefeed.Reorg: if _, ok := requestedTopics[ChainReorgTopic]; !ok { return nil diff --git a/beacon-chain/rpc/eth/light-client/BUILD.bazel b/beacon-chain/rpc/eth/light-client/BUILD.bazel index 4b1aee2d28cd..930c701901a5 100644 --- a/beacon-chain/rpc/eth/light-client/BUILD.bazel +++ b/beacon-chain/rpc/eth/light-client/BUILD.bazel @@ -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", diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index 3137eda4cd2c..49c28fa9379b 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -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 + } + finalizedRoot := bytesutil.ToBytes32(finalizedCheckpoint.Root) + finalizedBlock, err = s.Blocker.Block(ctx, finalizedRoot[:]) + if !shared.WriteBlockFetchError(w, block, errors.Wrap(err, "could not get finalized block")) { + return } - update, err := newLightClientFinalityUpdateFromBeaconState( - ctx, - state, - block, - attestedState, - finalizedBlock, - ) + 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) + httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError) return } - response := &structs.LightClientUpdateWithVersion{ + 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() } } diff --git a/beacon-chain/rpc/eth/light-client/handlers_test.go b/beacon-chain/rpc/eth/light-client/handlers_test.go index 245def3d2218..cac658e7aeed 100644 --- a/beacon-chain/rpc/eth/light-client/handlers_test.go +++ b/beacon-chain/rpc/eth/light-client/handlers_test.go @@ -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) diff --git a/beacon-chain/rpc/eth/light-client/helpers.go b/beacon-chain/rpc/eth/light-client/helpers.go index aa5f8a6b81dd..b30de84bce79 100644 --- a/beacon-chain/rpc/eth/light-client/helpers.go +++ b/beacon-chain/rpc/eth/light-client/helpers.go @@ -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 { diff --git a/testing/util/lightclient.go b/testing/util/lightclient.go index cece6018ed21..a4ca9b3e5abb 100644 --- a/testing/util/lightclient.go +++ b/testing/util/lightclient.go @@ -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") }