diff --git a/api/server/structs/BUILD.bazel b/api/server/structs/BUILD.bazel index c194d502ee02..54ed0b02a9e3 100644 --- a/api/server/structs/BUILD.bazel +++ b/api/server/structs/BUILD.bazel @@ -36,9 +36,8 @@ go_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", + "//runtime/version:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_pkg_errors//:go_default_library", diff --git a/api/server/structs/conversions.go b/api/server/structs/conversions.go index 9ed1f50e4e67..74af3c41aba5 100644 --- a/api/server/structs/conversions.go +++ b/api/server/structs/conversions.go @@ -1546,3 +1546,10 @@ func EventChainReorgFromV1(event *ethv1.EventChainReorg) *ChainReorgEvent { ExecutionOptimistic: event.ExecutionOptimistic, } } + +func SyncAggregateFromConsensus(sa *eth.SyncAggregate) *SyncAggregate { + return &SyncAggregate{ + SyncCommitteeBits: hexutil.Encode(sa.SyncCommitteeBits), + SyncCommitteeSignature: hexutil.Encode(sa.SyncCommitteeSignature), + } +} diff --git a/api/server/structs/conversions_lightclient.go b/api/server/structs/conversions_lightclient.go index 50e6281ef9b9..0c809c70b146 100644 --- a/api/server/structs/conversions_lightclient.go +++ b/api/server/structs/conversions_lightclient.go @@ -3,125 +3,153 @@ 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" + "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" ) -func LightClientUpdateFromConsensus(update *v2.LightClientUpdate) (*LightClientUpdate, error) { - attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) +func LightClientUpdateFromConsensus(update interfaces.LightClientUpdate) (*LightClientUpdate, error) { + attestedHeader, err := lightClientHeaderToJSON(update.AttestedHeader()) if err != nil { return nil, errors.Wrap(err, "could not marshal attested light client header") } - finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader) + finalizedHeader, err := lightClientHeaderToJSON(update.FinalizedHeader()) if err != nil { return nil, errors.Wrap(err, "could not marshal finalized light client header") } + finalityBranch := update.FinalityBranch() + + var scBranch [][32]byte + if update.Version() >= version.Electra { + b, err := update.NextSyncCommitteeBranchElectra() + if err != nil { + return nil, err + } + scBranch = b[:] + } else { + b, err := update.NextSyncCommitteeBranch() + if err != nil { + return nil, err + } + scBranch = b[:] + } return &LightClientUpdate{ AttestedHeader: attestedHeader, - NextSyncCommittee: SyncCommitteeFromConsensus(migration.V2SyncCommitteeToV1Alpha1(update.NextSyncCommittee)), - NextSyncCommitteeBranch: branchToJSON(update.NextSyncCommitteeBranch), + NextSyncCommittee: SyncCommitteeFromConsensus(update.NextSyncCommittee()), + NextSyncCommitteeBranch: branchToJSON(scBranch), FinalizedHeader: finalizedHeader, - FinalityBranch: branchToJSON(update.FinalityBranch), - SyncAggregate: syncAggregateToJSON(update.SyncAggregate), - SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10), + FinalityBranch: branchToJSON(finalityBranch[:]), + SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()), + SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()), }, nil } -func LightClientFinalityUpdateFromConsensus(update *v2.LightClientFinalityUpdate) (*LightClientFinalityUpdate, error) { - attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) +func LightClientFinalityUpdateFromConsensus(update interfaces.LightClientFinalityUpdate) (*LightClientFinalityUpdate, error) { + attestedHeader, err := lightClientHeaderToJSON(update.AttestedHeader()) if err != nil { return nil, errors.Wrap(err, "could not marshal attested light client header") } - finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader) + finalizedHeader, err := lightClientHeaderToJSON(update.FinalizedHeader()) if err != nil { return nil, errors.Wrap(err, "could not marshal finalized light client header") } + finalityBranch := update.FinalityBranch() return &LightClientFinalityUpdate{ AttestedHeader: attestedHeader, FinalizedHeader: finalizedHeader, - FinalityBranch: branchToJSON(update.FinalityBranch), - SyncAggregate: syncAggregateToJSON(update.SyncAggregate), - SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10), + FinalityBranch: branchToJSON(finalityBranch[:]), + SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()), + SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()), }, nil } -func LightClientOptimisticUpdateFromConsensus(update *v2.LightClientOptimisticUpdate) (*LightClientOptimisticUpdate, error) { - attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) +func LightClientOptimisticUpdateFromConsensus(update interfaces.LightClientOptimisticUpdate) (*LightClientOptimisticUpdate, error) { + attestedHeader, err := lightClientHeaderToJSON(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), + SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()), + SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()), }, nil } -func branchToJSON(branchBytes [][]byte) []string { +func branchToJSON[S [][32]byte](branchBytes S) []string { if branchBytes == nil { return nil } branch := make([]string, len(branchBytes)) for i, root := range branchBytes { - branch[i] = hexutil.Encode(root) + 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) { +func lightClientHeaderToJSON(header interfaces.LightClientHeader) (json.RawMessage, error) { // In the case that a finalizedHeader is nil. - if container == nil { + if header == nil { return nil, nil } - beacon, err := container.GetBeacon() - if err != nil { - return nil, errors.Wrap(err, "could not get beacon block header") - } - - var header any + var result 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) + switch v := header.Version(); v { + case version.Altair: + result = &LightClientHeader{Beacon: BeaconBlockHeaderFromConsensus(header.Beacon())} + case version.Capella: + exInterface, err := header.Execution() if err != nil { return nil, err } - header = &LightClientHeaderCapella{ - Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)), + ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderCapella) + if !ok { + return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderCapella{}) + } + execution, err := ExecutionPayloadHeaderCapellaFromConsensus(ex) + if err != nil { + return nil, err + } + executionBranch, err := header.ExecutionBranch() + if err != nil { + return nil, err + } + result = &LightClientHeaderCapella{ + Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()), Execution: execution, - ExecutionBranch: branchToJSON(t.HeaderCapella.ExecutionBranch), + ExecutionBranch: branchToJSON(executionBranch[:]), + } + case version.Deneb: + exInterface, err := header.Execution() + if err != nil { + return nil, err + } + ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderDeneb) + if !ok { + return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderDeneb{}) + } + execution, err := ExecutionPayloadHeaderDenebFromConsensus(ex) + if err != nil { + return nil, err } - case *v2.LightClientHeaderContainer_HeaderDeneb: - execution, err := ExecutionPayloadHeaderDenebFromConsensus(t.HeaderDeneb.Execution) + executionBranch, err := header.ExecutionBranch() if err != nil { return nil, err } - header = &LightClientHeaderDeneb{ - Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)), + result = &LightClientHeaderDeneb{ + Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()), Execution: execution, - ExecutionBranch: branchToJSON(t.HeaderDeneb.ExecutionBranch), + ExecutionBranch: branchToJSON(executionBranch[:]), } default: - return nil, fmt.Errorf("unsupported header type %T", t) + return nil, fmt.Errorf("unsupported header version %s", version.String(v)) } - return json.Marshal(header) + return json.Marshal(result) } diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 8f3da0a4236c..7b7a5f07fba7 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -129,7 +129,12 @@ func (s *Service) sendLightClientFeeds(cfg *postBlockProcessConfig) { } } -func (s *Service) tryPublishLightClientFinalityUpdate(ctx context.Context, signed interfaces.ReadOnlySignedBeaconBlock, finalized *forkchoicetypes.Checkpoint, postState state.BeaconState) { +func (s *Service) tryPublishLightClientFinalityUpdate( + ctx context.Context, + signed interfaces.ReadOnlySignedBeaconBlock, + finalized *forkchoicetypes.Checkpoint, + postState state.BeaconState, +) { if finalized.Epoch <= s.lastPublishedLightClientEpoch { return } @@ -182,15 +187,15 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte } } - update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState( + _, err = lightclient.NewLightClientFinalityUpdateFromBeaconState( ctx, + postState.Slot(), postState, signed, attestedState, attestedBlock, finalizedBlock, ) - if err != nil { return 0, errors.Wrap(err, "could not create light client update") } @@ -198,7 +203,8 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte // Return the result result := ðpbv2.LightClientFinalityUpdateWithVersion{ Version: ethpbv2.Version(signed.Version()), - Data: update, + // TODO: Get back to this when revisiting events + //Data: update, } // Send event @@ -222,14 +228,14 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in return 0, errors.Wrap(err, "could not get attested state") } - update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState( + _, err = lightclient.NewLightClientOptimisticUpdateFromBeaconState( ctx, + postState.Slot(), postState, signed, attestedState, attestedBlock, ) - if err != nil { return 0, errors.Wrap(err, "could not create light client update") } @@ -237,7 +243,8 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in // Return the result result := ðpbv2.LightClientOptimisticUpdateWithVersion{ Version: ethpbv2.Version(signed.Version()), - Data: update, + // TODO: Get back to this when revisiting events + //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 c7a264c71bb6..327e1922055f 100644 --- a/beacon-chain/core/light-client/BUILD.bazel +++ b/beacon-chain/core/light-client/BUILD.bazel @@ -6,19 +6,22 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client", visibility = ["//visibility:public"], deps = [ + "//beacon-chain/execution:go_default_library", "//beacon-chain/state:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types:go_default_library", "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", + "//consensus-types/light-client:go_default_library", + "//consensus-types/primitives:go_default_library", "//encoding/ssz:go_default_library", "//proto/engine/v1:go_default_library", - "//proto/eth/v1:go_default_library", - "//proto/eth/v2:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", "//runtime/version:go_default_library", "//time/slots:go_default_library", "@com_github_pkg_errors//:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/beacon-chain/core/light-client/lightclient.go b/beacon-chain/core/light-client/lightclient.go index 1173ec355331..7c60a163cf05 100644 --- a/beacon-chain/core/light-client/lightclient.go +++ b/beacon-chain/core/light-client/lightclient.go @@ -6,85 +6,75 @@ import ( "fmt" "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/execution" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/config/params" consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" + light_client "github.com/prysmaticlabs/prysm/v5/consensus-types/light-client" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/encoding/ssz" - v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" - ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" - ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/time/slots" + "google.golang.org/protobuf/proto" ) const ( - FinalityBranchNumOfLeaves = 6 - executionBranchNumOfLeaves = 4 + FinalityBranchNumOfLeaves = 6 ) -func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate { - finalityUpdate := ðpbv2.LightClientFinalityUpdate{ - AttestedHeader: update.AttestedHeader, - FinalizedHeader: update.FinalizedHeader, - FinalityBranch: update.FinalityBranch, - SyncAggregate: update.SyncAggregate, - SignatureSlot: update.SignatureSlot, - } - - return finalityUpdate -} - -func createLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate { - optimisticUpdate := ðpbv2.LightClientOptimisticUpdate{ - AttestedHeader: update.AttestedHeader, - SyncAggregate: update.SyncAggregate, - SignatureSlot: update.SignatureSlot, - } - - return optimisticUpdate -} - func NewLightClientFinalityUpdateFromBeaconState( ctx context.Context, + currentSlot primitives.Slot, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock, attestedState state.BeaconState, attestedBlock interfaces.ReadOnlySignedBeaconBlock, finalizedBlock interfaces.ReadOnlySignedBeaconBlock, -) (*ethpbv2.LightClientFinalityUpdate, error) { - update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock) +) (interfaces.LightClientFinalityUpdate, error) { + update, err := NewLightClientUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, finalizedBlock) if err != nil { return nil, err } - return createLightClientFinalityUpdate(update), nil + return light_client.NewFinalityUpdateFromUpdate(update) } func NewLightClientOptimisticUpdateFromBeaconState( ctx context.Context, + currentSlot primitives.Slot, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock, attestedState state.BeaconState, attestedBlock interfaces.ReadOnlySignedBeaconBlock, -) (*ethpbv2.LightClientOptimisticUpdate, error) { - update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, nil) +) (interfaces.LightClientOptimisticUpdate, error) { + update, err := NewLightClientUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, nil) if err != nil { return nil, err } - return createLightClientOptimisticUpdate(update), nil + return light_client.NewOptimisticUpdateFromUpdate(update) } +// To form a LightClientUpdate, the following historical states and blocks are needed: +// - state: the post state of any block with a post-Altair parent block +// - block: the corresponding block +// - attested_state: the post state of attested_block +// - attested_block: the block referred to by block.parent_root +// - finalized_block: the block referred to by attested_state.finalized_checkpoint.root, +// if locally available (may be unavailable, e.g., when using checkpoint sync, or if it was pruned locally) func NewLightClientUpdateFromBeaconState( ctx context.Context, + currentSlot primitives.Slot, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock, attestedState state.BeaconState, attestedBlock interfaces.ReadOnlySignedBeaconBlock, - finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) { + finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (interfaces.LightClientUpdate, error) { // assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH attestedEpoch := slots.ToEpoch(attestedState.Slot()) if attestedEpoch < params.BeaconConfig().AltairForkEpoch { @@ -129,7 +119,11 @@ func NewLightClientUpdateFromBeaconState( // 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) + return nil, fmt.Errorf( + "attested state slot %d not equal to attested latest block header slot %d", + attestedState.Slot(), + attestedState.LatestBlockHeader().Slot, + ) } // attested_header = attested_state.latest_block_header.copy() @@ -153,46 +147,56 @@ func NewLightClientUpdateFromBeaconState( } // assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root if attestedHeaderRoot != block.Block().ParentRoot() || attestedHeaderRoot != attestedBlockRoot { - return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x or attested block root %#x", attestedHeaderRoot, block.Block().ParentRoot(), attestedBlockRoot) + return nil, fmt.Errorf( + "attested header root %#x not equal to block parent root %#x or attested block root %#x", + attestedHeaderRoot, + block.Block().ParentRoot(), + attestedBlockRoot, + ) } // update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot) updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(attestedBlock.Block().Slot())) // update = LightClientUpdate() - result, err := createDefaultLightClientUpdate() + result, err := createDefaultLightClientUpdate(currentSlot) 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) - attestedLightClientHeader, err := BlockToLightClientHeader(attestedBlock) + attestedLightClientHeader, err := BlockToLightClientHeader(ctx, currentSlot, attestedBlock) if err != nil { return nil, errors.Wrap(err, "could not get attested light client header") } - result.AttestedHeader = attestedLightClientHeader + result.SetAttestedHeader(attestedLightClientHeader) // if update_attested_period == update_signature_period if updateAttestedPeriod == updateSignaturePeriod { + // update.next_sync_committee = attested_state.next_sync_committee tempNextSyncCommittee, err := attestedState.NextSyncCommittee() if err != nil { return nil, errors.Wrap(err, "could not get next sync committee") } - nextSyncCommittee := ðpbv2.SyncCommittee{ + nextSyncCommittee := &pb.SyncCommittee{ Pubkeys: tempNextSyncCommittee.Pubkeys, AggregatePubkey: tempNextSyncCommittee.AggregatePubkey, } + result.SetNextSyncCommittee(nextSyncCommittee) + + // update.next_sync_committee_branch = NextSyncCommitteeBranch( + // compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot))) nextSyncCommitteeBranch, err := attestedState.NextSyncCommitteeProof(ctx) if err != nil { return nil, errors.Wrap(err, "could not get next sync committee proof") } - - // 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 + if attestedBlock.Version() >= version.Electra { + if err = result.SetNextSyncCommitteeBranchElectra(nextSyncCommitteeBranch); err != nil { + return nil, errors.Wrap(err, "could not set next sync committee branch") + } + } else if err = result.SetNextSyncCommitteeBranch(nextSyncCommitteeBranch); err != nil { + return nil, errors.Wrap(err, "could not set next sync committee branch") + } } // if finalized_block is not None @@ -200,11 +204,11 @@ func NewLightClientUpdateFromBeaconState( // if finalized_block.message.slot != GENESIS_SLOT if finalizedBlock.Block().Slot() != 0 { // update.finalized_header = block_to_light_client_header(finalized_block) - finalizedLightClientHeader, err := BlockToLightClientHeader(finalizedBlock) + finalizedLightClientHeader, err := BlockToLightClientHeader(ctx, currentSlot, finalizedBlock) if err != nil { return nil, errors.Wrap(err, "could not get finalized light client header") } - result.FinalizedHeader = finalizedLightClientHeader + result.SetFinalizedHeader(finalizedLightClientHeader) } else { // assert attested_state.finalized_checkpoint.root == Bytes32() if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) { @@ -218,49 +222,83 @@ func NewLightClientUpdateFromBeaconState( if err != nil { return nil, errors.Wrap(err, "could not get finalized root proof") } - result.FinalityBranch = finalityBranch + if err = result.SetFinalityBranch(finalityBranch); err != nil { + return nil, errors.Wrap(err, "could not set finality branch") + } } // update.sync_aggregate = block.message.body.sync_aggregate - result.SyncAggregate = ðpbv1.SyncAggregate{ + result.SetSyncAggregate(&pb.SyncAggregate{ SyncCommitteeBits: syncAggregate.SyncCommitteeBits, SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature, - } + }) // update.signature_slot = block.message.slot - result.SignatureSlot = block.Block().Slot() + result.SetSignatureSlot(block.Block().Slot()) return result, nil } -func createDefaultLightClientUpdate() (*ethpbv2.LightClientUpdate, error) { +func createDefaultLightClientUpdate(currentSlot primitives.Slot) (interfaces.LightClientUpdate, error) { + currentEpoch := slots.ToEpoch(currentSlot) + syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize pubKeys := make([][]byte, syncCommitteeSize) for i := uint64(0); i < syncCommitteeSize; i++ { pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength) } - nextSyncCommittee := ðpbv2.SyncCommittee{ + nextSyncCommittee := &pb.SyncCommittee{ Pubkeys: pubKeys, AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength), } - nextSyncCommitteeBranch := make([][]byte, fieldparams.SyncCommitteeBranchDepth) - for i := 0; i < fieldparams.SyncCommitteeBranchDepth; i++ { + + var nextSyncCommitteeBranch [][]byte + if currentEpoch >= params.BeaconConfig().ElectraForkEpoch { + nextSyncCommitteeBranch = make([][]byte, fieldparams.SyncCommitteeBranchDepthElectra) + } else { + nextSyncCommitteeBranch = make([][]byte, fieldparams.SyncCommitteeBranchDepth) + } + for i := 0; i < len(nextSyncCommitteeBranch); i++ { nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength) } - executionBranch := make([][]byte, executionBranchNumOfLeaves) - for i := 0; i < executionBranchNumOfLeaves; i++ { + + executionBranch := make([][]byte, fieldparams.ExecutionBranchDepth) + for i := 0; i < fieldparams.ExecutionBranchDepth; i++ { executionBranch[i] = make([]byte, 32) } - finalityBranch := make([][]byte, FinalityBranchNumOfLeaves) - for i := 0; i < FinalityBranchNumOfLeaves; i++ { + finalityBranch := make([][]byte, fieldparams.FinalityBranchDepth) + for i := 0; i < fieldparams.FinalityBranchDepth; i++ { finalityBranch[i] = make([]byte, 32) } - return ðpbv2.LightClientUpdate{ - NextSyncCommittee: nextSyncCommittee, - NextSyncCommitteeBranch: nextSyncCommitteeBranch, - FinalityBranch: finalityBranch, - }, nil + var m proto.Message + if currentEpoch < params.BeaconConfig().CapellaForkEpoch { + m = &pb.LightClientUpdateAltair{ + NextSyncCommittee: nextSyncCommittee, + NextSyncCommitteeBranch: nextSyncCommitteeBranch, + FinalityBranch: finalityBranch, + } + } else if currentEpoch < params.BeaconConfig().DenebForkEpoch { + m = &pb.LightClientUpdateCapella{ + NextSyncCommittee: nextSyncCommittee, + NextSyncCommitteeBranch: nextSyncCommitteeBranch, + FinalityBranch: finalityBranch, + } + } else if currentEpoch < params.BeaconConfig().ElectraForkEpoch { + m = &pb.LightClientUpdateDeneb{ + NextSyncCommittee: nextSyncCommittee, + NextSyncCommitteeBranch: nextSyncCommitteeBranch, + FinalityBranch: finalityBranch, + } + } else { + m = &pb.LightClientUpdateElectra{ + NextSyncCommittee: nextSyncCommittee, + NextSyncCommitteeBranch: nextSyncCommitteeBranch, + FinalityBranch: finalityBranch, + } + } + + return light_client.NewWrappedUpdate(m) } func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) { @@ -299,47 +337,14 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) { return withdrawalsRoot, nil } -func BlockToLightClientHeader(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderContainer, error) { - switch block.Version() { - case version.Altair, version.Bellatrix: - altairHeader, err := blockToLightClientHeaderAltair(block) - if err != nil { - return nil, errors.Wrap(err, "could not get header") - } - return ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ - HeaderAltair: altairHeader, - }, - }, nil - case version.Capella: - capellaHeader, err := blockToLightClientHeaderCapella(context.Background(), block) - if err != nil { - return nil, errors.Wrap(err, "could not get capella header") - } - return ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ - HeaderCapella: capellaHeader, - }, - }, nil - case version.Deneb, version.Electra: - denebHeader, err := blockToLightClientHeaderDeneb(context.Background(), block) - if err != nil { - return nil, errors.Wrap(err, "could not get header") - } - return ðpbv2.LightClientHeaderContainer{ - Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ - HeaderDeneb: denebHeader, - }, - }, nil - default: - return nil, fmt.Errorf("unsupported block version %s", version.String(block.Version())) - } -} - -func blockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeader, error) { - if block.Version() < version.Altair { - return nil, fmt.Errorf("block version is %s instead of Altair", version.String(block.Version())) - } +func BlockToLightClientHeader( + ctx context.Context, + currentSlot primitives.Slot, + block interfaces.ReadOnlySignedBeaconBlock, +) (interfaces.LightClientHeader, error) { + var m proto.Message + currentEpoch := slots.ToEpoch(currentSlot) + blockEpoch := slots.ToEpoch(block.Block().Slot()) parentRoot := block.Block().ParentRoot() stateRoot := block.Block().StateRoot() @@ -348,147 +353,172 @@ func blockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock) return nil, errors.Wrap(err, "could not get body root") } - return ðpbv2.LightClientHeader{ - Beacon: ðpbv1.BeaconBlockHeader{ - Slot: block.Block().Slot(), - ProposerIndex: block.Block().ProposerIndex(), - ParentRoot: parentRoot[:], - StateRoot: stateRoot[:], - BodyRoot: bodyRoot[:], - }, - }, nil -} + if currentEpoch < params.BeaconConfig().CapellaForkEpoch { + m = &pb.LightClientHeaderAltair{ + Beacon: &pb.BeaconBlockHeader{ + Slot: block.Block().Slot(), + ProposerIndex: block.Block().ProposerIndex(), + ParentRoot: parentRoot[:], + StateRoot: stateRoot[:], + BodyRoot: bodyRoot[:], + }, + } + } else if currentEpoch < params.BeaconConfig().DenebForkEpoch { + var payloadHeader *enginev1.ExecutionPayloadHeaderCapella + var payloadProof [][]byte -func blockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderCapella, error) { - if block.Version() < version.Capella { - return nil, fmt.Errorf("block version is %s instead of Capella", version.String(block.Version())) - } + if blockEpoch < params.BeaconConfig().CapellaForkEpoch { + var ok bool - payload, err := block.Block().Body().Execution() - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload") - } + p, err := execution.EmptyExecutionPayload(version.Capella) + if err != nil { + return nil, errors.Wrap(err, "could not get payload header") + } + payloadHeader, ok = p.(*enginev1.ExecutionPayloadHeaderCapella) + if !ok { + return nil, errors.Wrapf(err, "payload header type %T is not %T", payloadHeader, &enginev1.ExecutionPayloadHeaderCapella{}) + } + payloadProof = emptyPayloadProof() + } else { + payload, err := block.Block().Body().Execution() + if err != nil { + return nil, errors.Wrap(err, "could not get execution payload") + } + transactionsRoot, err := ComputeTransactionsRoot(payload) + if err != nil { + return nil, errors.Wrap(err, "could not get transactions root") + } + withdrawalsRoot, err := ComputeWithdrawalsRoot(payload) + if err != nil { + return nil, errors.Wrap(err, "could not get withdrawals root") + } - transactionsRoot, err := ComputeTransactionsRoot(payload) - if err != nil { - return nil, err - } - withdrawalsRoot, err := ComputeWithdrawalsRoot(payload) - if err != nil { - return nil, err - } + payloadHeader = &enginev1.ExecutionPayloadHeaderCapella{ + ParentHash: payload.ParentHash(), + FeeRecipient: payload.FeeRecipient(), + StateRoot: payload.StateRoot(), + ReceiptsRoot: payload.ReceiptsRoot(), + LogsBloom: payload.LogsBloom(), + PrevRandao: payload.PrevRandao(), + BlockNumber: payload.BlockNumber(), + GasLimit: payload.GasLimit(), + GasUsed: payload.GasUsed(), + Timestamp: payload.Timestamp(), + ExtraData: payload.ExtraData(), + BaseFeePerGas: payload.BaseFeePerGas(), + BlockHash: payload.BlockHash(), + TransactionsRoot: transactionsRoot, + WithdrawalsRoot: withdrawalsRoot, + } - executionHeader := &v11.ExecutionPayloadHeaderCapella{ - ParentHash: payload.ParentHash(), - FeeRecipient: payload.FeeRecipient(), - StateRoot: payload.StateRoot(), - ReceiptsRoot: payload.ReceiptsRoot(), - LogsBloom: payload.LogsBloom(), - PrevRandao: payload.PrevRandao(), - BlockNumber: payload.BlockNumber(), - GasLimit: payload.GasLimit(), - GasUsed: payload.GasUsed(), - Timestamp: payload.Timestamp(), - ExtraData: payload.ExtraData(), - BaseFeePerGas: payload.BaseFeePerGas(), - BlockHash: payload.BlockHash(), - TransactionsRoot: transactionsRoot, - WithdrawalsRoot: withdrawalsRoot, - } + payloadProof, err = blocks.PayloadProof(ctx, block.Block()) + if err != nil { + return nil, errors.Wrap(err, "could not get execution payload proof") + } + } - executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block()) - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload proof") - } + m = &pb.LightClientHeaderCapella{ + Beacon: &pb.BeaconBlockHeader{ + Slot: block.Block().Slot(), + ProposerIndex: block.Block().ProposerIndex(), + ParentRoot: parentRoot[:], + StateRoot: stateRoot[:], + BodyRoot: bodyRoot[:], + }, + Execution: payloadHeader, + ExecutionBranch: payloadProof, + } + } else { + var payloadHeader *enginev1.ExecutionPayloadHeaderDeneb + var payloadProof [][]byte - parentRoot := block.Block().ParentRoot() - stateRoot := block.Block().StateRoot() - bodyRoot, err := block.Block().Body().HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, "could not get body root") - } + if blockEpoch < params.BeaconConfig().CapellaForkEpoch { + var ok bool - return ðpbv2.LightClientHeaderCapella{ - Beacon: ðpbv1.BeaconBlockHeader{ - Slot: block.Block().Slot(), - ProposerIndex: block.Block().ProposerIndex(), - ParentRoot: parentRoot[:], - StateRoot: stateRoot[:], - BodyRoot: bodyRoot[:], - }, - Execution: executionHeader, - ExecutionBranch: executionPayloadProof, - }, nil -} + p, err := execution.EmptyExecutionPayload(version.Deneb) + if err != nil { + return nil, errors.Wrap(err, "could not get payload header") + } + payloadHeader, ok = p.(*enginev1.ExecutionPayloadHeaderDeneb) + if !ok { + return nil, errors.Wrapf(err, "payload header type %T is not %T", payloadHeader, &enginev1.ExecutionPayloadHeaderDeneb{}) + } + payloadProof = emptyPayloadProof() + } else { + payload, err := block.Block().Body().Execution() + if err != nil { + return nil, errors.Wrap(err, "could not get execution payload") + } + transactionsRoot, err := ComputeTransactionsRoot(payload) + if err != nil { + return nil, errors.Wrap(err, "could not get transactions root") + } + withdrawalsRoot, err := ComputeWithdrawalsRoot(payload) + if err != nil { + return nil, errors.Wrap(err, "could not get withdrawals root") + } -func blockToLightClientHeaderDeneb(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderDeneb, error) { - if block.Version() < version.Deneb { - return nil, fmt.Errorf("block version is %s instead of Deneb/Electra", version.String(block.Version())) - } + var blobGasUsed uint64 + var excessBlobGas uint64 + + if blockEpoch >= params.BeaconConfig().DenebForkEpoch { + blobGasUsed, err = payload.BlobGasUsed() + if err != nil { + return nil, errors.Wrap(err, "could not get blob gas used") + } + excessBlobGas, err = payload.ExcessBlobGas() + if err != nil { + return nil, errors.Wrap(err, "could not get excess blob gas") + } + } - payload, err := block.Block().Body().Execution() - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload") - } + payloadHeader = &enginev1.ExecutionPayloadHeaderDeneb{ + ParentHash: payload.ParentHash(), + FeeRecipient: payload.FeeRecipient(), + StateRoot: payload.StateRoot(), + ReceiptsRoot: payload.ReceiptsRoot(), + LogsBloom: payload.LogsBloom(), + PrevRandao: payload.PrevRandao(), + BlockNumber: payload.BlockNumber(), + GasLimit: payload.GasLimit(), + GasUsed: payload.GasUsed(), + Timestamp: payload.Timestamp(), + ExtraData: payload.ExtraData(), + BaseFeePerGas: payload.BaseFeePerGas(), + BlockHash: payload.BlockHash(), + TransactionsRoot: transactionsRoot, + WithdrawalsRoot: withdrawalsRoot, + BlobGasUsed: blobGasUsed, + ExcessBlobGas: excessBlobGas, + } - transactionsRoot, err := ComputeTransactionsRoot(payload) - if err != nil { - return nil, err - } - withdrawalsRoot, err := ComputeWithdrawalsRoot(payload) - if err != nil { - return nil, err - } - blobGasUsed, err := payload.BlobGasUsed() - if err != nil { - return nil, errors.Wrap(err, "could not get blob gas used") - } - excessBlobGas, err := payload.ExcessBlobGas() - if err != nil { - return nil, errors.Wrap(err, "could not get excess blob gas") - } + payloadProof, err = blocks.PayloadProof(ctx, block.Block()) + if err != nil { + return nil, errors.Wrap(err, "could not get execution payload proof") + } + } - executionHeader := &v11.ExecutionPayloadHeaderDeneb{ - ParentHash: payload.ParentHash(), - FeeRecipient: payload.FeeRecipient(), - StateRoot: payload.StateRoot(), - ReceiptsRoot: payload.ReceiptsRoot(), - LogsBloom: payload.LogsBloom(), - PrevRandao: payload.PrevRandao(), - BlockNumber: payload.BlockNumber(), - GasLimit: payload.GasLimit(), - GasUsed: payload.GasUsed(), - Timestamp: payload.Timestamp(), - ExtraData: payload.ExtraData(), - BaseFeePerGas: payload.BaseFeePerGas(), - BlockHash: payload.BlockHash(), - TransactionsRoot: transactionsRoot, - WithdrawalsRoot: withdrawalsRoot, - BlobGasUsed: blobGasUsed, - ExcessBlobGas: excessBlobGas, + m = &pb.LightClientHeaderDeneb{ + Beacon: &pb.BeaconBlockHeader{ + Slot: block.Block().Slot(), + ProposerIndex: block.Block().ProposerIndex(), + ParentRoot: parentRoot[:], + StateRoot: stateRoot[:], + BodyRoot: bodyRoot[:], + }, + Execution: payloadHeader, + ExecutionBranch: payloadProof, + } } - executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block()) - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload proof") - } + return light_client.NewWrappedHeader(m) +} - parentRoot := block.Block().ParentRoot() - stateRoot := block.Block().StateRoot() - bodyRoot, err := block.Block().Body().HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, "could not get body root") +func emptyPayloadProof() [][]byte { + branch := interfaces.LightClientExecutionBranch{} + proof := make([][]byte, len(branch)) + for i, b := range branch { + proof[i] = b[:] } - - return ðpbv2.LightClientHeaderDeneb{ - Beacon: ðpbv1.BeaconBlockHeader{ - Slot: block.Block().Slot(), - ProposerIndex: block.Block().ProposerIndex(), - ParentRoot: parentRoot[:], - StateRoot: stateRoot[:], - BodyRoot: bodyRoot[:], - }, - Execution: executionHeader, - ExecutionBranch: executionPayloadProof, - }, nil + return proof } diff --git a/beacon-chain/db/iface/BUILD.bazel b/beacon-chain/db/iface/BUILD.bazel index 993d1fd84c98..81929a26a47d 100644 --- a/beacon-chain/db/iface/BUILD.bazel +++ b/beacon-chain/db/iface/BUILD.bazel @@ -18,7 +18,6 @@ go_library( "//consensus-types/primitives:go_default_library", "//monitoring/backup:go_default_library", "//proto/dbval:go_default_library", - "//proto/eth/v2:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", ], diff --git a/beacon-chain/db/iface/interface.go b/beacon-chain/db/iface/interface.go index b75960ef553c..fc2ef7af4faa 100644 --- a/beacon-chain/db/iface/interface.go +++ b/beacon-chain/db/iface/interface.go @@ -7,8 +7,6 @@ import ( "context" "io" - ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" - "github.com/ethereum/go-ethereum/common" "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters" slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types" @@ -59,8 +57,8 @@ type ReadOnlyDatabase interface { FeeRecipientByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (common.Address, error) RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) // light client operations - LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]*ethpbv2.LightClientUpdateWithVersion, error) - LightClientUpdate(ctx context.Context, period uint64) (*ethpbv2.LightClientUpdateWithVersion, error) + LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]interfaces.LightClientUpdate, error) + LightClientUpdate(ctx context.Context, period uint64) (interfaces.LightClientUpdate, error) // origin checkpoint sync support OriginCheckpointBlockRoot(ctx context.Context) ([32]byte, error) @@ -98,7 +96,7 @@ type NoHeadAccessDatabase interface { SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []primitives.ValidatorIndex, addrs []common.Address) error SaveRegistrationsByValidatorIDs(ctx context.Context, ids []primitives.ValidatorIndex, regs []*ethpb.ValidatorRegistrationV1) error // light client operations - SaveLightClientUpdate(ctx context.Context, period uint64, update *ethpbv2.LightClientUpdateWithVersion) error + SaveLightClientUpdate(ctx context.Context, period uint64, update interfaces.LightClientUpdate) error CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint primitives.Slot) error } diff --git a/beacon-chain/db/kv/BUILD.bazel b/beacon-chain/db/kv/BUILD.bazel index 732da2fb5b2a..0a95e714aeb3 100644 --- a/beacon-chain/db/kv/BUILD.bazel +++ b/beacon-chain/db/kv/BUILD.bazel @@ -44,6 +44,7 @@ go_library( "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", + "//consensus-types/light-client:go_default_library", "//consensus-types/primitives:go_default_library", "//container/slice:go_default_library", "//encoding/bytesutil:go_default_library", @@ -53,7 +54,6 @@ go_library( "//monitoring/tracing:go_default_library", "//monitoring/tracing/trace:go_default_library", "//proto/dbval:go_default_library", - "//proto/eth/v2:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/version:go_default_library", "//time:go_default_library", diff --git a/beacon-chain/db/kv/lightclient.go b/beacon-chain/db/kv/lightclient.go index 3c7bef3ff5f1..d7bbc1796814 100644 --- a/beacon-chain/db/kv/lightclient.go +++ b/beacon-chain/db/kv/lightclient.go @@ -5,35 +5,41 @@ import ( "encoding/binary" "fmt" + "github.com/golang/snappy" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" + light_client "github.com/prysmaticlabs/prysm/v5/consensus-types/light-client" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" - ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" bolt "go.etcd.io/bbolt" + "google.golang.org/protobuf/proto" ) -func (s *Store) SaveLightClientUpdate(ctx context.Context, period uint64, update *ethpbv2.LightClientUpdateWithVersion) error { - ctx, span := trace.StartSpan(ctx, "BeaconDB.saveLightClientUpdate") +func (s *Store) SaveLightClientUpdate(ctx context.Context, period uint64, update interfaces.LightClientUpdate) error { + _, span := trace.StartSpan(ctx, "BeaconDB.SaveLightClientUpdate") defer span.End() return s.db.Update(func(tx *bolt.Tx) error { bkt := tx.Bucket(lightClientUpdatesBucket) - updateMarshalled, err := encode(ctx, update) + enc, err := encodeLightClientUpdate(update) if err != nil { return err } - return bkt.Put(bytesutil.Uint64ToBytesBigEndian(period), updateMarshalled) + return bkt.Put(bytesutil.Uint64ToBytesBigEndian(period), enc) }) } -func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]*ethpbv2.LightClientUpdateWithVersion, error) { - ctx, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdates") +func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod uint64) (map[uint64]interfaces.LightClientUpdate, error) { + _, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdates") defer span.End() if startPeriod > endPeriod { return nil, fmt.Errorf("start period %d is greater than end period %d", startPeriod, endPeriod) } - updates := make(map[uint64]*ethpbv2.LightClientUpdateWithVersion) + updates := make(map[uint64]interfaces.LightClientUpdate) err := s.db.View(func(tx *bolt.Tx) error { bkt := tx.Bucket(lightClientUpdatesBucket) c := bkt.Cursor() @@ -46,11 +52,11 @@ func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod u for k, v := c.Seek(bytesutil.Uint64ToBytesBigEndian(startPeriod)); k != nil && binary.BigEndian.Uint64(k) <= endPeriod; k, v = c.Next() { currentPeriod := binary.BigEndian.Uint64(k) - var update ethpbv2.LightClientUpdateWithVersion - if err := decode(ctx, v, &update); err != nil { + update, err := decodeLightClientUpdate(v) + if err != nil { return err } - updates[currentPeriod] = &update + updates[currentPeriod] = update } return nil @@ -62,18 +68,87 @@ func (s *Store) LightClientUpdates(ctx context.Context, startPeriod, endPeriod u return updates, err } -func (s *Store) LightClientUpdate(ctx context.Context, period uint64) (*ethpbv2.LightClientUpdateWithVersion, error) { - ctx, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdate") +func (s *Store) LightClientUpdate(ctx context.Context, period uint64) (interfaces.LightClientUpdate, error) { + _, span := trace.StartSpan(ctx, "BeaconDB.LightClientUpdate") defer span.End() - var update ethpbv2.LightClientUpdateWithVersion + var update interfaces.LightClientUpdate err := s.db.View(func(tx *bolt.Tx) error { bkt := tx.Bucket(lightClientUpdatesBucket) updateBytes := bkt.Get(bytesutil.Uint64ToBytesBigEndian(period)) if updateBytes == nil { return nil } - return decode(ctx, updateBytes, &update) + var err error + update, err = decodeLightClientUpdate(updateBytes) + return err }) - return &update, err + return update, err +} + +func encodeLightClientUpdate(update interfaces.LightClientUpdate) ([]byte, error) { + key, err := keyForLightClientUpdate(update) + if err != nil { + return nil, err + } + enc, err := update.MarshalSSZ() + if err != nil { + return nil, errors.Wrap(err, "could not marshal light client update") + } + fullEnc := make([]byte, len(key)+len(enc)) + copy(fullEnc[len(key):], enc) + return snappy.Encode(nil, fullEnc), nil +} + +func decodeLightClientUpdate(enc []byte) (interfaces.LightClientUpdate, error) { + var err error + enc, err = snappy.Decode(nil, enc) + if err != nil { + return nil, errors.Wrap(err, "could not snappy decode light client update") + } + var m proto.Message + switch { + case hasAltairKey(enc): + update := ðpb.LightClientUpdateAltair{} + if err := update.UnmarshalSSZ(enc[len(altairKey):]); err != nil { + return nil, errors.Wrap(err, "could not unmarshal Altair light client update") + } + m = update + case hasCapellaKey(enc): + update := ðpb.LightClientUpdateCapella{} + if err := update.UnmarshalSSZ(enc[len(capellaKey):]); err != nil { + return nil, errors.Wrap(err, "could not unmarshal Capella light client update") + } + m = update + case hasDenebKey(enc): + update := ðpb.LightClientUpdateDeneb{} + if err := update.UnmarshalSSZ(enc[len(denebKey):]); err != nil { + return nil, errors.Wrap(err, "could not unmarshal Deneb light client update") + } + m = update + case hasElectraKey(enc): + update := ðpb.LightClientUpdateElectra{} + if err := update.UnmarshalSSZ(enc[len(electraKey):]); err != nil { + return nil, errors.Wrap(err, "could not unmarshal Electra light client update") + } + m = update + default: + return nil, errors.New("decoding of saved light client update is unsupported") + } + return light_client.NewWrappedUpdate(m) +} + +func keyForLightClientUpdate(update interfaces.LightClientUpdate) ([]byte, error) { + switch v := update.Version(); v { + case version.Electra: + return electraKey, nil + case version.Deneb: + return denebKey, nil + case version.Capella: + return capellaKey, nil + case version.Altair: + return altairKey, nil + default: + return nil, fmt.Errorf("unsupported light client update version %s", version.String(v)) + } } diff --git a/beacon-chain/execution/engine_client.go b/beacon-chain/execution/engine_client.go index 2dfc479f4214..e3a295424083 100644 --- a/beacon-chain/execution/engine_client.go +++ b/beacon-chain/execution/engine_client.go @@ -687,7 +687,7 @@ func tDStringToUint256(td string) (*uint256.Int, error) { return i, nil } -func buildEmptyExecutionPayload(v int) (proto.Message, error) { +func EmptyExecutionPayload(v int) (proto.Message, error) { switch v { case version.Bellatrix: return &pb.ExecutionPayload{ diff --git a/beacon-chain/execution/payload_body.go b/beacon-chain/execution/payload_body.go index 17aba3329e0f..4021bb2339f2 100644 --- a/beacon-chain/execution/payload_body.go +++ b/beacon-chain/execution/payload_body.go @@ -205,7 +205,7 @@ func (r *blindedBlockReconstructor) requestBodiesByHash(ctx context.Context, cli func (r *blindedBlockReconstructor) payloadForHeader(header interfaces.ExecutionData, v int) (proto.Message, error) { bodyKey := bytesutil.ToBytes32(header.BlockHash()) if bodyKey == params.BeaconConfig().ZeroHash { - payload, err := buildEmptyExecutionPayload(v) + payload, err := EmptyExecutionPayload(v) if err != nil { return nil, errors.Wrapf(err, "failed to reconstruct payload for body hash %#x", bodyKey) } diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index f6b47009582b..fada0a671505 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -848,10 +848,11 @@ func (*Service) configEndpoints() []endpoint { func (s *Service) lightClientEndpoints(blocker lookup.Blocker, stater lookup.Stater) []endpoint { server := &lightclient.Server{ - Blocker: blocker, - Stater: stater, - HeadFetcher: s.cfg.HeadFetcher, - BeaconDB: s.cfg.BeaconDB, + Blocker: blocker, + Stater: stater, + HeadFetcher: s.cfg.HeadFetcher, + ChainInfoFetcher: s.cfg.ChainInfoFetcher, + BeaconDB: s.cfg.BeaconDB, } const namespace = "lightclient" diff --git a/beacon-chain/rpc/eth/events/events.go b/beacon-chain/rpc/eth/events/events.go index 7698d2fb9017..f50687fe9436 100644 --- a/beacon-chain/rpc/eth/events/events.go +++ b/beacon-chain/rpc/eth/events/events.go @@ -485,28 +485,30 @@ func (s *Server) lazyReaderForEvent(ctx context.Context, event *feed.Event, topi return jsonMarshalReader(eventName, structs.FinalizedCheckpointEventFromV1(v)) }, nil case *ethpbv2.LightClientFinalityUpdateWithVersion: - cv, err := structs.LightClientFinalityUpdateFromConsensus(v.Data) + // TODO: Get back to this when revisiting events + /*cv, err := structs.LightClientFinalityUpdateFromConsensus(v.Data) if err != nil { return nil, errors.Wrap(err, "LightClientFinalityUpdateWithVersion event conversion failure") } ev := &structs.LightClientFinalityUpdateEvent{ Version: version.String(int(v.Version)), Data: cv, - } + }*/ return func() io.Reader { - return jsonMarshalReader(eventName, ev) + return jsonMarshalReader(eventName, struct{}{}) }, nil case *ethpbv2.LightClientOptimisticUpdateWithVersion: - cv, err := structs.LightClientOptimisticUpdateFromConsensus(v.Data) + // TODO: Get back to this when revisiting events + /*cv, err := structs.LightClientOptimisticUpdateFromConsensus(v.Data) if err != nil { return nil, errors.Wrap(err, "LightClientOptimisticUpdateWithVersion event conversion failure") } ev := &structs.LightClientOptimisticUpdateEvent{ Version: version.String(int(v.Version)), Data: cv, - } + }*/ return func() io.Reader { - return jsonMarshalReader(eventName, ev) + return jsonMarshalReader(eventName, struct{}{}) }, nil case *ethpb.EventChainReorg: return func() io.Reader { diff --git a/beacon-chain/rpc/eth/light-client/BUILD.bazel b/beacon-chain/rpc/eth/light-client/BUILD.bazel index 85b46a07ecc4..d0fa6cb7a801 100644 --- a/beacon-chain/rpc/eth/light-client/BUILD.bazel +++ b/beacon-chain/rpc/eth/light-client/BUILD.bazel @@ -24,8 +24,6 @@ go_library( "//consensus-types/primitives:go_default_library", "//monitoring/tracing/trace:go_default_library", "//network/httputil: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 245d703eaafd..3bc6909486da 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -47,7 +47,7 @@ func (s *Server) GetLightClientBootstrap(w http.ResponseWriter, req *http.Reques return } - bootstrap, err := createLightClientBootstrap(ctx, state, blk) + bootstrap, err := createLightClientBootstrap(ctx, s.ChainInfoFetcher.CurrentSlot(), state, blk) if err != nil { httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError) return @@ -201,6 +201,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R update, err := newLightClientUpdateFromBeaconState( ctx, + s.ChainInfoFetcher.CurrentSlot(), state, block, attestedState, @@ -268,7 +269,7 @@ func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.R return } - update, err := newLightClientFinalityUpdateFromBeaconState(ctx, st, block, attestedState, attestedBlock, finalizedBlock) + update, err := newLightClientFinalityUpdateFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), st, block, attestedState, attestedBlock, finalizedBlock) if err != nil { httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError) return @@ -313,7 +314,7 @@ func (s *Server) GetLightClientOptimisticUpdate(w http.ResponseWriter, req *http return } - update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, st, block, attestedState, attestedBlock) + update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, s.ChainInfoFetcher.CurrentSlot(), st, block, attestedState, attestedBlock) if err != nil { httputil.HandleError(w, "Could not get light client optimistic update: "+err.Error(), http.StatusInternalServerError) return diff --git a/beacon-chain/rpc/eth/light-client/helpers.go b/beacon-chain/rpc/eth/light-client/helpers.go index ce989a7d5672..f1f6cbdf7af1 100644 --- a/beacon-chain/rpc/eth/light-client/helpers.go +++ b/beacon-chain/rpc/eth/light-client/helpers.go @@ -7,7 +7,8 @@ import ( "reflect" "github.com/pkg/errors" - "github.com/prysmaticlabs/prysm/v5/proto/migration" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client" "github.com/prysmaticlabs/prysm/v5/runtime/version" @@ -15,28 +16,17 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/prysmaticlabs/prysm/v5/api/server/structs" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" - fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" - v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" "github.com/prysmaticlabs/prysm/v5/time/slots" ) -func createLightClientBootstrap(ctx context.Context, state state.BeaconState, blk interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) { - switch blk.Version() { - case version.Phase0: - return nil, fmt.Errorf("light client bootstrap is not supported for phase0") - case version.Altair, version.Bellatrix: - return createLightClientBootstrapAltair(ctx, state, blk) - case version.Capella: - return createLightClientBootstrapCapella(ctx, state, blk) - case version.Deneb, version.Electra: - return createLightClientBootstrapDeneb(ctx, state, blk) - } - return nil, fmt.Errorf("unsupported block version %s", version.String(blk.Version())) -} - -func createLightClientBootstrapAltair(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) { +func createLightClientBootstrap( + ctx context.Context, + currentSlot primitives.Slot, + state state.BeaconState, + block interfaces.ReadOnlySignedBeaconBlock, +) (*structs.LightClientBootstrap, error) { // assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH if slots.ToEpoch(state.Slot()) < params.BeaconConfig().AltairForkEpoch { return nil, fmt.Errorf("light client bootstrap is not supported before Altair, invalid slot %d", state.Slot()) @@ -68,82 +58,13 @@ func createLightClientBootstrapAltair(ctx context.Context, state state.BeaconSta return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot) } - lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block) - if err != nil { - return nil, errors.Wrap(err, "could not convert block to light client header") - } - lightClientHeader := lightClientHeaderContainer.GetHeaderAltair() - - apiLightClientHeader := &structs.LightClientHeader{ - Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)), - } - - headerJSON, err := json.Marshal(apiLightClientHeader) - if err != nil { - return nil, errors.Wrap(err, "could not convert header to raw message") - } - currentSyncCommittee, err := state.CurrentSyncCommittee() - if err != nil { - return nil, errors.Wrap(err, "could not get current sync committee") - } - currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not get current sync committee proof") - } - - branch := make([]string, fieldparams.SyncCommitteeBranchDepth) - for i, proof := range currentSyncCommitteeProof { - branch[i] = hexutil.Encode(proof) - } - result := &structs.LightClientBootstrap{ - Header: headerJSON, - CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee), - CurrentSyncCommitteeBranch: branch, - } - - return result, nil -} - -func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) { - // assert compute_epoch_at_slot(state.slot) >= CAPELLA_FORK_EPOCH - if slots.ToEpoch(state.Slot()) < params.BeaconConfig().CapellaForkEpoch { - return nil, fmt.Errorf("creating Capella light client bootstrap is not supported before Capella, invalid slot %d", state.Slot()) - } - - // assert state.slot == state.latest_block_header.slot - latestBlockHeader := state.LatestBlockHeader() - if state.Slot() != latestBlockHeader.Slot { - return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot) - } - - // header.state_root = hash_tree_root(state) - stateRoot, err := state.HashTreeRoot(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not get state root") - } - latestBlockHeader.StateRoot = stateRoot[:] - - // assert hash_tree_root(header) == hash_tree_root(block.message) - latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, "could not get latest block header root") - } - beaconBlockRoot, err := block.Block().HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, "could not get block root") - } - if latestBlockHeaderRoot != beaconBlockRoot { - return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot) - } - - lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block) + lightClientHeader, err := lightclient.BlockToLightClientHeader(ctx, currentSlot, block) if err != nil { return nil, errors.Wrap(err, "could not convert block to light client header") } - lightClientHeader := lightClientHeaderContainer.GetHeaderCapella() apiLightClientHeader := &structs.LightClientHeader{ - Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)), + Beacon: structs.BeaconBlockHeaderFromConsensus(lightClientHeader.Beacon()), } headerJSON, err := json.Marshal(apiLightClientHeader) @@ -159,83 +80,16 @@ func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconSt return nil, errors.Wrap(err, "could not get current sync committee proof") } - branch := make([]string, fieldparams.SyncCommitteeBranchDepth) - for i, proof := range currentSyncCommitteeProof { - branch[i] = hexutil.Encode(proof) - } - result := &structs.LightClientBootstrap{ - Header: headerJSON, - CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee), - CurrentSyncCommitteeBranch: branch, - } - - return result, nil -} - -func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) { - // assert compute_epoch_at_slot(state.slot) >= DENEB_FORK_EPOCH - if slots.ToEpoch(state.Slot()) < params.BeaconConfig().DenebForkEpoch { - return nil, fmt.Errorf("creating Deneb light client bootstrap is not supported before Deneb, invalid slot %d", state.Slot()) - } - - // assert state.slot == state.latest_block_header.slot - latestBlockHeader := state.LatestBlockHeader() - if state.Slot() != latestBlockHeader.Slot { - return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot) - } - - // header.state_root = hash_tree_root(state) - stateRoot, err := state.HashTreeRoot(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not get state root") - } - latestBlockHeader.StateRoot = stateRoot[:] - - // assert hash_tree_root(header) == hash_tree_root(block.message) - latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, "could not get latest block header root") - } - beaconBlockRoot, err := block.Block().HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, "could not get block root") - } - if latestBlockHeaderRoot != beaconBlockRoot { - return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot) - } - - lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block) - if err != nil { - return nil, errors.Wrap(err, "could not convert block to light client header") - } - lightClientHeader := lightClientHeaderContainer.GetHeaderDeneb() - - apiLightClientHeader := &structs.LightClientHeader{ - Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)), - } - - headerJSON, err := json.Marshal(apiLightClientHeader) - if err != nil { - return nil, errors.Wrap(err, "could not convert header to raw message") - } - currentSyncCommittee, err := state.CurrentSyncCommittee() - if err != nil { - return nil, errors.Wrap(err, "could not get current sync committee") - } - currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not get current sync committee proof") - } var branch []string - switch block.Version() { - case version.Deneb: - branch = make([]string, fieldparams.SyncCommitteeBranchDepth) - case version.Electra: + if state.Version() >= version.Electra { branch = make([]string, fieldparams.SyncCommitteeBranchDepthElectra) + } else { + branch = make([]string, fieldparams.SyncCommitteeBranchDepth) } for i, proof := range currentSyncCommitteeProof { branch[i] = hexutil.Encode(proof) } + result := &structs.LightClientBootstrap{ Header: headerJSON, CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee), @@ -247,13 +101,14 @@ func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconStat func newLightClientUpdateFromBeaconState( ctx context.Context, + currentSlot primitives.Slot, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock, attestedState state.BeaconState, attestedBlock interfaces.ReadOnlySignedBeaconBlock, finalizedBlock interfaces.ReadOnlySignedBeaconBlock, ) (*structs.LightClientUpdate, error) { - result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock) + result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, finalizedBlock) if err != nil { return nil, err } @@ -263,13 +118,14 @@ func newLightClientUpdateFromBeaconState( func newLightClientFinalityUpdateFromBeaconState( ctx context.Context, + currentSlot primitives.Slot, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock, attestedState state.BeaconState, attestedBlock interfaces.ReadOnlySignedBeaconBlock, finalizedBlock interfaces.ReadOnlySignedBeaconBlock, ) (*structs.LightClientFinalityUpdate, error) { - result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock) + result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock, finalizedBlock) if err != nil { return nil, err } @@ -279,12 +135,13 @@ func newLightClientFinalityUpdateFromBeaconState( func newLightClientOptimisticUpdateFromBeaconState( ctx context.Context, + currentSlot primitives.Slot, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock, attestedState state.BeaconState, attestedBlock interfaces.ReadOnlySignedBeaconBlock, ) (*structs.LightClientOptimisticUpdate, error) { - result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock) + result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, currentSlot, state, block, attestedState, attestedBlock) if err != nil { return nil, err } @@ -292,20 +149,29 @@ func newLightClientOptimisticUpdateFromBeaconState( return structs.LightClientOptimisticUpdateFromConsensus(result) } -func IsSyncCommitteeUpdate(update *v2.LightClientUpdate) bool { - nextSyncCommitteeBranch := make([][]byte, fieldparams.SyncCommitteeBranchDepth) - return !reflect.DeepEqual(update.NextSyncCommitteeBranch, nextSyncCommitteeBranch) +func HasRelevantSyncCommittee(update interfaces.LightClientUpdate) (bool, error) { + if update.Version() >= version.Electra { + branch, err := update.NextSyncCommitteeBranchElectra() + if err != nil { + return false, err + } + return !reflect.DeepEqual(branch, interfaces.LightClientSyncCommitteeBranchElectra{}), nil + } + branch, err := update.NextSyncCommitteeBranch() + if err != nil { + return false, err + } + return !reflect.DeepEqual(branch, interfaces.LightClientSyncCommitteeBranch{}), nil } -func IsFinalityUpdate(update *v2.LightClientUpdate) bool { - finalityBranch := make([][]byte, lightclient.FinalityBranchNumOfLeaves) - return !reflect.DeepEqual(update.FinalityBranch, finalityBranch) +func HasFinality(update interfaces.LightClientUpdate) bool { + return !reflect.DeepEqual(update.FinalityBranch(), interfaces.LightClientFinalityBranch{}) } -func IsBetterUpdate(newUpdate, oldUpdate *v2.LightClientUpdate) (bool, error) { - maxActiveParticipants := newUpdate.SyncAggregate.SyncCommitteeBits.Len() - newNumActiveParticipants := newUpdate.SyncAggregate.SyncCommitteeBits.Count() - oldNumActiveParticipants := oldUpdate.SyncAggregate.SyncCommitteeBits.Count() +func IsBetterUpdate(newUpdate, oldUpdate interfaces.LightClientUpdate) (bool, error) { + maxActiveParticipants := newUpdate.SyncAggregate().SyncCommitteeBits.Len() + newNumActiveParticipants := newUpdate.SyncAggregate().SyncCommitteeBits.Count() + oldNumActiveParticipants := oldUpdate.SyncAggregate().SyncCommitteeBits.Count() newHasSupermajority := newNumActiveParticipants*3 >= maxActiveParticipants*2 oldHasSupermajority := oldNumActiveParticipants*3 >= maxActiveParticipants*2 @@ -316,43 +182,45 @@ func IsBetterUpdate(newUpdate, oldUpdate *v2.LightClientUpdate) (bool, error) { return newNumActiveParticipants > oldNumActiveParticipants, nil } - newUpdateAttestedHeaderBeacon, err := newUpdate.AttestedHeader.GetBeacon() + newUpdateAttestedHeaderBeacon := newUpdate.AttestedHeader().Beacon() + oldUpdateAttestedHeaderBeacon := oldUpdate.AttestedHeader().Beacon() + + // Compare presence of relevant sync committee + newHasRelevantSyncCommittee, err := HasRelevantSyncCommittee(newUpdate) if err != nil { - return false, errors.Wrap(err, "could not get attested header beacon") + return false, err } - oldUpdateAttestedHeaderBeacon, err := oldUpdate.AttestedHeader.GetBeacon() + newHasRelevantSyncCommittee = newHasRelevantSyncCommittee && + (slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(newUpdate.SignatureSlot()))) + oldHasRelevantSyncCommittee, err := HasRelevantSyncCommittee(oldUpdate) if err != nil { - return false, errors.Wrap(err, "could not get attested header beacon") + return false, err } - - // Compare presence of relevant sync committee - newHasRelevantSyncCommittee := IsSyncCommitteeUpdate(newUpdate) && (slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(newUpdate.SignatureSlot))) - oldHasRelevantSyncCommittee := IsSyncCommitteeUpdate(oldUpdate) && (slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdate.SignatureSlot))) + oldHasRelevantSyncCommittee = oldHasRelevantSyncCommittee && + (slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdate.SignatureSlot()))) if newHasRelevantSyncCommittee != oldHasRelevantSyncCommittee { return newHasRelevantSyncCommittee, nil } // Compare indication of any finality - newHasFinality := IsFinalityUpdate(newUpdate) - oldHasFinality := IsFinalityUpdate(oldUpdate) + newHasFinality := HasFinality(newUpdate) + oldHasFinality := HasFinality(oldUpdate) if newHasFinality != oldHasFinality { return newHasFinality, nil } - newUpdateFinalizedHeaderBeacon, err := newUpdate.FinalizedHeader.GetBeacon() - if err != nil { - return false, errors.Wrap(err, "could not get finalized header beacon") - } - oldUpdateFinalizedHeaderBeacon, err := oldUpdate.FinalizedHeader.GetBeacon() - if err != nil { - return false, errors.Wrap(err, "could not get finalized header beacon") - } + newUpdateFinalizedHeaderBeacon := newUpdate.FinalizedHeader().Beacon() + oldUpdateFinalizedHeaderBeacon := oldUpdate.FinalizedHeader().Beacon() // Compare sync committee finality if newHasFinality { - newHasSyncCommitteeFinality := slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateFinalizedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot)) - oldHasSyncCommitteeFinality := slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateFinalizedHeaderBeacon.Slot)) == slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot)) + newHasSyncCommitteeFinality := + slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateFinalizedHeaderBeacon.Slot)) == + slots.SyncCommitteePeriod(slots.ToEpoch(newUpdateAttestedHeaderBeacon.Slot)) + oldHasSyncCommitteeFinality := + slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateFinalizedHeaderBeacon.Slot)) == + slots.SyncCommitteePeriod(slots.ToEpoch(oldUpdateAttestedHeaderBeacon.Slot)) if newHasSyncCommitteeFinality != oldHasSyncCommitteeFinality { return newHasSyncCommitteeFinality, nil @@ -368,5 +236,6 @@ func IsBetterUpdate(newUpdate, oldUpdate *v2.LightClientUpdate) (bool, error) { if newUpdateAttestedHeaderBeacon.Slot != oldUpdateAttestedHeaderBeacon.Slot { return newUpdateAttestedHeaderBeacon.Slot < oldUpdateAttestedHeaderBeacon.Slot, nil } - return newUpdate.SignatureSlot < oldUpdate.SignatureSlot, nil + + return newUpdate.SignatureSlot() < oldUpdate.SignatureSlot(), nil } diff --git a/beacon-chain/rpc/eth/light-client/server.go b/beacon-chain/rpc/eth/light-client/server.go index e0773a306405..84b061379fc1 100644 --- a/beacon-chain/rpc/eth/light-client/server.go +++ b/beacon-chain/rpc/eth/light-client/server.go @@ -7,8 +7,9 @@ import ( ) type Server struct { - Blocker lookup.Blocker - Stater lookup.Stater - HeadFetcher blockchain.HeadFetcher - BeaconDB db.HeadAccessDatabase + Blocker lookup.Blocker + Stater lookup.Stater + HeadFetcher blockchain.HeadFetcher + ChainInfoFetcher blockchain.ChainInfoFetcher + BeaconDB db.HeadAccessDatabase } diff --git a/consensus-types/interfaces/light_client.go b/consensus-types/interfaces/light_client.go index 217a086497d4..994470c65a42 100644 --- a/consensus-types/interfaces/light_client.go +++ b/consensus-types/interfaces/light_client.go @@ -5,6 +5,7 @@ import ( fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "google.golang.org/protobuf/proto" ) type LightClientExecutionBranch = [fieldparams.ExecutionBranchDepth][fieldparams.RootLength]byte @@ -14,6 +15,7 @@ type LightClientFinalityBranch = [fieldparams.FinalityBranchDepth][fieldparams.R type LightClientHeader interface { ssz.Marshaler + Proto() proto.Message Version() int Beacon() *pb.BeaconBlockHeader Execution() (ExecutionData, error) @@ -31,19 +33,29 @@ type LightClientBootstrap interface { type LightClientUpdate interface { ssz.Marshaler + Proto() proto.Message Version() int AttestedHeader() LightClientHeader + SetAttestedHeader(header LightClientHeader) NextSyncCommittee() *pb.SyncCommittee + SetNextSyncCommittee(sc *pb.SyncCommittee) NextSyncCommitteeBranch() (LightClientSyncCommitteeBranch, error) + SetNextSyncCommitteeBranch(branch [][]byte) error NextSyncCommitteeBranchElectra() (LightClientSyncCommitteeBranchElectra, error) + SetNextSyncCommitteeBranchElectra(branch [][]byte) error FinalizedHeader() LightClientHeader + SetFinalizedHeader(header LightClientHeader) FinalityBranch() LightClientFinalityBranch + SetFinalityBranch(branch [][]byte) error SyncAggregate() *pb.SyncAggregate + SetSyncAggregate(sa *pb.SyncAggregate) SignatureSlot() primitives.Slot + SetSignatureSlot(slot primitives.Slot) } type LightClientFinalityUpdate interface { ssz.Marshaler + Proto() proto.Message Version() int AttestedHeader() LightClientHeader FinalizedHeader() LightClientHeader @@ -54,6 +66,7 @@ type LightClientFinalityUpdate interface { type LightClientOptimisticUpdate interface { ssz.Marshaler + Proto() proto.Message Version() int AttestedHeader() LightClientHeader SyncAggregate() *pb.SyncAggregate diff --git a/consensus-types/light-client/finality_update.go b/consensus-types/light-client/finality_update.go index 37de560e60ed..dad1259f2e75 100644 --- a/consensus-types/light-client/finality_update.go +++ b/consensus-types/light-client/finality_update.go @@ -28,6 +28,65 @@ func NewWrappedFinalityUpdate(m proto.Message) (interfaces.LightClientFinalityUp } } +func NewFinalityUpdateFromUpdate(update interfaces.LightClientUpdate) (interfaces.LightClientFinalityUpdate, error) { + switch t := update.(type) { + case *updateAltair: + return &finalityUpdateAltair{ + p: &pb.LightClientFinalityUpdateAltair{ + AttestedHeader: t.p.AttestedHeader, + FinalizedHeader: t.p.FinalizedHeader, + FinalityBranch: t.p.FinalityBranch, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + finalizedHeader: t.finalizedHeader, + finalityBranch: t.finalityBranch, + }, nil + case *updateCapella: + return &finalityUpdateCapella{ + p: &pb.LightClientFinalityUpdateCapella{ + AttestedHeader: t.p.AttestedHeader, + FinalizedHeader: t.p.FinalizedHeader, + FinalityBranch: t.p.FinalityBranch, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + finalizedHeader: t.finalizedHeader, + finalityBranch: t.finalityBranch, + }, nil + case *updateDeneb: + return &finalityUpdateDeneb{ + p: &pb.LightClientFinalityUpdateDeneb{ + AttestedHeader: t.p.AttestedHeader, + FinalizedHeader: t.p.FinalizedHeader, + FinalityBranch: t.p.FinalityBranch, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + finalizedHeader: t.finalizedHeader, + finalityBranch: t.finalityBranch, + }, nil + case *updateElectra: + return &finalityUpdateDeneb{ + p: &pb.LightClientFinalityUpdateDeneb{ + AttestedHeader: t.p.AttestedHeader, + FinalizedHeader: t.p.FinalizedHeader, + FinalityBranch: t.p.FinalityBranch, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + finalizedHeader: t.finalizedHeader, + finalityBranch: t.finalityBranch, + }, nil + default: + return nil, fmt.Errorf("unsupported type %T", t) + } +} + type finalityUpdateAltair struct { p *pb.LightClientFinalityUpdateAltair attestedHeader interfaces.LightClientHeader @@ -78,6 +137,10 @@ func (u *finalityUpdateAltair) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *finalityUpdateAltair) Proto() proto.Message { + return u.p +} + func (u *finalityUpdateAltair) Version() int { return version.Altair } @@ -152,6 +215,10 @@ func (u *finalityUpdateCapella) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *finalityUpdateCapella) Proto() proto.Message { + return u.p +} + func (u *finalityUpdateCapella) Version() int { return version.Capella } @@ -226,6 +293,10 @@ func (u *finalityUpdateDeneb) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *finalityUpdateDeneb) Proto() proto.Message { + return u.p +} + func (u *finalityUpdateDeneb) Version() int { return version.Deneb } diff --git a/consensus-types/light-client/header.go b/consensus-types/light-client/header.go index 496a48424c7e..32b344227480 100644 --- a/consensus-types/light-client/header.go +++ b/consensus-types/light-client/header.go @@ -53,6 +53,10 @@ func (h *headerAltair) SizeSSZ() int { return h.p.SizeSSZ() } +func (h *headerAltair) Proto() proto.Message { + return h.p +} + func (h *headerAltair) Version() int { return version.Altair } @@ -114,6 +118,10 @@ func (h *headerCapella) SizeSSZ() int { return h.p.SizeSSZ() } +func (h *headerCapella) Proto() proto.Message { + return h.p +} + func (h *headerCapella) Version() int { return version.Capella } @@ -175,6 +183,10 @@ func (h *headerDeneb) SizeSSZ() int { return h.p.SizeSSZ() } +func (h *headerDeneb) Proto() proto.Message { + return h.p +} + func (h *headerDeneb) Version() int { return version.Deneb } diff --git a/consensus-types/light-client/helpers.go b/consensus-types/light-client/helpers.go index c2fc9b05922c..0d100314a4f9 100644 --- a/consensus-types/light-client/helpers.go +++ b/consensus-types/light-client/helpers.go @@ -4,12 +4,11 @@ import ( "fmt" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" - "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ) type branchConstraint interface { - ~interfaces.LightClientExecutionBranch | ~interfaces.LightClientSyncCommitteeBranch | ~interfaces.LightClientFinalityBranch + [4][32]byte | [5][32]byte | [6][32]byte } func createBranch[T branchConstraint](name string, input [][]byte, depth int) (T, error) { diff --git a/consensus-types/light-client/optimistic_update.go b/consensus-types/light-client/optimistic_update.go index f1f43d12cfa4..dd15ba02267e 100644 --- a/consensus-types/light-client/optimistic_update.go +++ b/consensus-types/light-client/optimistic_update.go @@ -27,12 +27,55 @@ func NewWrappedOptimisticUpdate(m proto.Message) (interfaces.LightClientOptimist } } -type OptimisticUpdateAltair struct { +func NewOptimisticUpdateFromUpdate(update interfaces.LightClientUpdate) (interfaces.LightClientOptimisticUpdate, error) { + switch t := update.(type) { + case *updateAltair: + return &optimisticUpdateAltair{ + p: &pb.LightClientOptimisticUpdateAltair{ + AttestedHeader: t.p.AttestedHeader, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + }, nil + case *updateCapella: + return &optimisticUpdateCapella{ + p: &pb.LightClientOptimisticUpdateCapella{ + AttestedHeader: t.p.AttestedHeader, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + }, nil + case *updateDeneb: + return &optimisticUpdateDeneb{ + p: &pb.LightClientOptimisticUpdateDeneb{ + AttestedHeader: t.p.AttestedHeader, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + }, nil + case *updateElectra: + return &optimisticUpdateDeneb{ + p: &pb.LightClientOptimisticUpdateDeneb{ + AttestedHeader: t.p.AttestedHeader, + SyncAggregate: t.p.SyncAggregate, + SignatureSlot: t.p.SignatureSlot, + }, + attestedHeader: t.attestedHeader, + }, nil + default: + return nil, fmt.Errorf("unsupported type %T", t) + } +} + +type optimisticUpdateAltair struct { p *pb.LightClientOptimisticUpdateAltair attestedHeader interfaces.LightClientHeader } -var _ interfaces.LightClientOptimisticUpdate = &OptimisticUpdateAltair{} +var _ interfaces.LightClientOptimisticUpdate = &optimisticUpdateAltair{} func NewWrappedOptimisticUpdateAltair(p *pb.LightClientOptimisticUpdateAltair) (interfaces.LightClientOptimisticUpdate, error) { if p == nil { @@ -43,46 +86,50 @@ func NewWrappedOptimisticUpdateAltair(p *pb.LightClientOptimisticUpdateAltair) ( return nil, err } - return &OptimisticUpdateAltair{ + return &optimisticUpdateAltair{ p: p, attestedHeader: attestedHeader, }, nil } -func (u *OptimisticUpdateAltair) MarshalSSZTo(dst []byte) ([]byte, error) { +func (u *optimisticUpdateAltair) MarshalSSZTo(dst []byte) ([]byte, error) { return u.p.MarshalSSZTo(dst) } -func (u *OptimisticUpdateAltair) MarshalSSZ() ([]byte, error) { +func (u *optimisticUpdateAltair) MarshalSSZ() ([]byte, error) { return u.p.MarshalSSZ() } -func (u *OptimisticUpdateAltair) SizeSSZ() int { +func (u *optimisticUpdateAltair) SizeSSZ() int { return u.p.SizeSSZ() } -func (u *OptimisticUpdateAltair) Version() int { +func (u *optimisticUpdateAltair) Proto() proto.Message { + return u.p +} + +func (u *optimisticUpdateAltair) Version() int { return version.Altair } -func (u *OptimisticUpdateAltair) AttestedHeader() interfaces.LightClientHeader { +func (u *optimisticUpdateAltair) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } -func (u *OptimisticUpdateAltair) SyncAggregate() *pb.SyncAggregate { +func (u *optimisticUpdateAltair) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } -func (u *OptimisticUpdateAltair) SignatureSlot() primitives.Slot { +func (u *optimisticUpdateAltair) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } -type OptimisticUpdateCapella struct { +type optimisticUpdateCapella struct { p *pb.LightClientOptimisticUpdateCapella attestedHeader interfaces.LightClientHeader } -var _ interfaces.LightClientOptimisticUpdate = &OptimisticUpdateCapella{} +var _ interfaces.LightClientOptimisticUpdate = &optimisticUpdateCapella{} func NewWrappedOptimisticUpdateCapella(p *pb.LightClientOptimisticUpdateCapella) (interfaces.LightClientOptimisticUpdate, error) { if p == nil { @@ -93,46 +140,50 @@ func NewWrappedOptimisticUpdateCapella(p *pb.LightClientOptimisticUpdateCapella) return nil, err } - return &OptimisticUpdateCapella{ + return &optimisticUpdateCapella{ p: p, attestedHeader: attestedHeader, }, nil } -func (u *OptimisticUpdateCapella) MarshalSSZTo(dst []byte) ([]byte, error) { +func (u *optimisticUpdateCapella) MarshalSSZTo(dst []byte) ([]byte, error) { return u.p.MarshalSSZTo(dst) } -func (u *OptimisticUpdateCapella) MarshalSSZ() ([]byte, error) { +func (u *optimisticUpdateCapella) MarshalSSZ() ([]byte, error) { return u.p.MarshalSSZ() } -func (u *OptimisticUpdateCapella) SizeSSZ() int { +func (u *optimisticUpdateCapella) SizeSSZ() int { return u.p.SizeSSZ() } -func (u *OptimisticUpdateCapella) Version() int { +func (u *optimisticUpdateCapella) Proto() proto.Message { + return u.p +} + +func (u *optimisticUpdateCapella) Version() int { return version.Capella } -func (u *OptimisticUpdateCapella) AttestedHeader() interfaces.LightClientHeader { +func (u *optimisticUpdateCapella) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } -func (u *OptimisticUpdateCapella) SyncAggregate() *pb.SyncAggregate { +func (u *optimisticUpdateCapella) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } -func (u *OptimisticUpdateCapella) SignatureSlot() primitives.Slot { +func (u *optimisticUpdateCapella) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } -type OptimisticUpdateDeneb struct { +type optimisticUpdateDeneb struct { p *pb.LightClientOptimisticUpdateDeneb attestedHeader interfaces.LightClientHeader } -var _ interfaces.LightClientOptimisticUpdate = &OptimisticUpdateDeneb{} +var _ interfaces.LightClientOptimisticUpdate = &optimisticUpdateDeneb{} func NewWrappedOptimisticUpdateDeneb(p *pb.LightClientOptimisticUpdateDeneb) (interfaces.LightClientOptimisticUpdate, error) { if p == nil { @@ -143,36 +194,40 @@ func NewWrappedOptimisticUpdateDeneb(p *pb.LightClientOptimisticUpdateDeneb) (in return nil, err } - return &OptimisticUpdateDeneb{ + return &optimisticUpdateDeneb{ p: p, attestedHeader: attestedHeader, }, nil } -func (u *OptimisticUpdateDeneb) MarshalSSZTo(dst []byte) ([]byte, error) { +func (u *optimisticUpdateDeneb) MarshalSSZTo(dst []byte) ([]byte, error) { return u.p.MarshalSSZTo(dst) } -func (u *OptimisticUpdateDeneb) MarshalSSZ() ([]byte, error) { +func (u *optimisticUpdateDeneb) MarshalSSZ() ([]byte, error) { return u.p.MarshalSSZ() } -func (u *OptimisticUpdateDeneb) SizeSSZ() int { +func (u *optimisticUpdateDeneb) SizeSSZ() int { return u.p.SizeSSZ() } -func (u *OptimisticUpdateDeneb) Version() int { +func (u *optimisticUpdateDeneb) Proto() proto.Message { + return u.p +} + +func (u *optimisticUpdateDeneb) Version() int { return version.Deneb } -func (u *OptimisticUpdateDeneb) AttestedHeader() interfaces.LightClientHeader { +func (u *optimisticUpdateDeneb) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } -func (u *OptimisticUpdateDeneb) SyncAggregate() *pb.SyncAggregate { +func (u *optimisticUpdateDeneb) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } -func (u *OptimisticUpdateDeneb) SignatureSlot() primitives.Slot { +func (u *optimisticUpdateDeneb) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } diff --git a/consensus-types/light-client/update.go b/consensus-types/light-client/update.go index 66a3403f1896..81ebf87f9c69 100644 --- a/consensus-types/light-client/update.go +++ b/consensus-types/light-client/update.go @@ -23,6 +23,8 @@ func NewWrappedUpdate(m proto.Message) (interfaces.LightClientUpdate, error) { return NewWrappedUpdateCapella(t) case *pb.LightClientUpdateDeneb: return NewWrappedUpdateDeneb(t) + case *pb.LightClientUpdateElectra: + return NewWrappedUpdateElectra(t) default: return nil, fmt.Errorf("cannot construct light client update from type %T", t) } @@ -46,10 +48,15 @@ func NewWrappedUpdateAltair(p *pb.LightClientUpdateAltair) (interfaces.LightClie if err != nil { return nil, err } - finalizedHeader, err := NewWrappedHeaderAltair(p.FinalizedHeader) - if err != nil { - return nil, err + + var finalizedHeader interfaces.LightClientHeader + if p.FinalizedHeader != nil { + finalizedHeader, err = NewWrappedHeaderAltair(p.FinalizedHeader) + if err != nil { + return nil, err + } } + scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranch]( "sync committee", p.NextSyncCommitteeBranch, @@ -88,6 +95,10 @@ func (u *updateAltair) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *updateAltair) Proto() proto.Message { + return u.p +} + func (u *updateAltair) Version() int { return version.Altair } @@ -96,34 +107,76 @@ func (u *updateAltair) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } +func (u *updateAltair) SetAttestedHeader(header interfaces.LightClientHeader) { + u.attestedHeader = header +} + func (u *updateAltair) NextSyncCommittee() *pb.SyncCommittee { return u.p.NextSyncCommittee } +func (u *updateAltair) SetNextSyncCommittee(sc *pb.SyncCommittee) { + u.p.NextSyncCommittee = sc +} + func (u *updateAltair) NextSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { return u.nextSyncCommitteeBranch, nil } +func (u *updateAltair) SetNextSyncCommitteeBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientSyncCommitteeBranch]("sync committee", branch, fieldparams.SyncCommitteeBranchDepth) + if err != nil { + return err + } + u.nextSyncCommitteeBranch = b + return nil +} + func (u *updateAltair) NextSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { return [6][32]byte{}, consensustypes.ErrNotSupported("NextSyncCommitteeBranchElectra", version.Altair) } +func (u *updateAltair) SetNextSyncCommitteeBranchElectra([][]byte) error { + return consensustypes.ErrNotSupported("SetNextSyncCommitteeBranchElectra", version.Altair) +} + func (u *updateAltair) FinalizedHeader() interfaces.LightClientHeader { return u.finalizedHeader } +func (u *updateAltair) SetFinalizedHeader(header interfaces.LightClientHeader) { + u.finalizedHeader = header +} + func (u *updateAltair) FinalityBranch() interfaces.LightClientFinalityBranch { return u.finalityBranch } +func (u *updateAltair) SetFinalityBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) + if err != nil { + return err + } + u.finalityBranch = b + return nil +} + func (u *updateAltair) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } +func (u *updateAltair) SetSyncAggregate(sa *pb.SyncAggregate) { + u.p.SyncAggregate = sa +} + func (u *updateAltair) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } +func (u *updateAltair) SetSignatureSlot(slot primitives.Slot) { + u.p.SignatureSlot = slot +} + type updateCapella struct { p *pb.LightClientUpdateCapella attestedHeader interfaces.LightClientHeader @@ -142,10 +195,15 @@ func NewWrappedUpdateCapella(p *pb.LightClientUpdateCapella) (interfaces.LightCl if err != nil { return nil, err } - finalizedHeader, err := NewWrappedHeaderCapella(p.FinalizedHeader) - if err != nil { - return nil, err + + var finalizedHeader interfaces.LightClientHeader + if p.FinalizedHeader != nil { + finalizedHeader, err = NewWrappedHeaderCapella(p.FinalizedHeader) + if err != nil { + return nil, err + } } + scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranch]( "sync committee", p.NextSyncCommitteeBranch, @@ -184,6 +242,10 @@ func (u *updateCapella) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *updateCapella) Proto() proto.Message { + return u.p +} + func (u *updateCapella) Version() int { return version.Capella } @@ -192,34 +254,76 @@ func (u *updateCapella) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } +func (u *updateCapella) SetAttestedHeader(header interfaces.LightClientHeader) { + u.attestedHeader = header +} + func (u *updateCapella) NextSyncCommittee() *pb.SyncCommittee { return u.p.NextSyncCommittee } +func (u *updateCapella) SetNextSyncCommittee(sc *pb.SyncCommittee) { + u.p.NextSyncCommittee = sc +} + func (u *updateCapella) NextSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { return u.nextSyncCommitteeBranch, nil } +func (u *updateCapella) SetNextSyncCommitteeBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientSyncCommitteeBranch]("sync committee", branch, fieldparams.SyncCommitteeBranchDepth) + if err != nil { + return err + } + u.nextSyncCommitteeBranch = b + return nil +} + func (u *updateCapella) NextSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { return [6][32]byte{}, consensustypes.ErrNotSupported("NextSyncCommitteeBranchElectra", version.Capella) } +func (u *updateCapella) SetNextSyncCommitteeBranchElectra([][]byte) error { + return consensustypes.ErrNotSupported("SetNextSyncCommitteeBranchElectra", version.Capella) +} + func (u *updateCapella) FinalizedHeader() interfaces.LightClientHeader { return u.finalizedHeader } +func (u *updateCapella) SetFinalizedHeader(header interfaces.LightClientHeader) { + u.finalizedHeader = header +} + func (u *updateCapella) FinalityBranch() interfaces.LightClientFinalityBranch { return u.finalityBranch } +func (u *updateCapella) SetFinalityBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) + if err != nil { + return err + } + u.finalityBranch = b + return nil +} + func (u *updateCapella) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } +func (u *updateCapella) SetSyncAggregate(sa *pb.SyncAggregate) { + u.p.SyncAggregate = sa +} + func (u *updateCapella) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } +func (u *updateCapella) SetSignatureSlot(slot primitives.Slot) { + u.p.SignatureSlot = slot +} + type updateDeneb struct { p *pb.LightClientUpdateDeneb attestedHeader interfaces.LightClientHeader @@ -238,10 +342,15 @@ func NewWrappedUpdateDeneb(p *pb.LightClientUpdateDeneb) (interfaces.LightClient if err != nil { return nil, err } - finalizedHeader, err := NewWrappedHeaderDeneb(p.FinalizedHeader) - if err != nil { - return nil, err + + var finalizedHeader interfaces.LightClientHeader + if p.FinalizedHeader != nil { + finalizedHeader, err = NewWrappedHeaderDeneb(p.FinalizedHeader) + if err != nil { + return nil, err + } } + scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranch]( "sync committee", p.NextSyncCommitteeBranch, @@ -280,6 +389,10 @@ func (u *updateDeneb) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *updateDeneb) Proto() proto.Message { + return u.p +} + func (u *updateDeneb) Version() int { return version.Deneb } @@ -288,34 +401,76 @@ func (u *updateDeneb) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } +func (u *updateDeneb) SetAttestedHeader(header interfaces.LightClientHeader) { + u.attestedHeader = header +} + func (u *updateDeneb) NextSyncCommittee() *pb.SyncCommittee { return u.p.NextSyncCommittee } +func (u *updateDeneb) SetNextSyncCommittee(sc *pb.SyncCommittee) { + u.p.NextSyncCommittee = sc +} + func (u *updateDeneb) NextSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { return u.nextSyncCommitteeBranch, nil } +func (u *updateDeneb) SetNextSyncCommitteeBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientSyncCommitteeBranch]("sync committee", branch, fieldparams.SyncCommitteeBranchDepth) + if err != nil { + return err + } + u.nextSyncCommitteeBranch = b + return nil +} + func (u *updateDeneb) NextSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { return [6][32]byte{}, consensustypes.ErrNotSupported("NextSyncCommitteeBranchElectra", version.Deneb) } +func (u *updateDeneb) SetNextSyncCommitteeBranchElectra([][]byte) error { + return consensustypes.ErrNotSupported("SetNextSyncCommitteeBranchElectra", version.Deneb) +} + func (u *updateDeneb) FinalizedHeader() interfaces.LightClientHeader { return u.finalizedHeader } +func (u *updateDeneb) SetFinalizedHeader(header interfaces.LightClientHeader) { + u.finalizedHeader = header +} + func (u *updateDeneb) FinalityBranch() interfaces.LightClientFinalityBranch { return u.finalityBranch } +func (u *updateDeneb) SetFinalityBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) + if err != nil { + return err + } + u.finalityBranch = b + return nil +} + func (u *updateDeneb) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } +func (u *updateDeneb) SetSyncAggregate(sa *pb.SyncAggregate) { + u.p.SyncAggregate = sa +} + func (u *updateDeneb) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } +func (u *updateDeneb) SetSignatureSlot(slot primitives.Slot) { + u.p.SignatureSlot = slot +} + type updateElectra struct { p *pb.LightClientUpdateElectra attestedHeader interfaces.LightClientHeader @@ -334,10 +489,15 @@ func NewWrappedUpdateElectra(p *pb.LightClientUpdateElectra) (interfaces.LightCl if err != nil { return nil, err } - finalizedHeader, err := NewWrappedHeaderDeneb(p.FinalizedHeader) - if err != nil { - return nil, err + + var finalizedHeader interfaces.LightClientHeader + if p.FinalizedHeader != nil { + finalizedHeader, err = NewWrappedHeaderDeneb(p.FinalizedHeader) + if err != nil { + return nil, err + } } + scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranchElectra]( "sync committee", p.NextSyncCommitteeBranch, @@ -376,6 +536,10 @@ func (u *updateElectra) SizeSSZ() int { return u.p.SizeSSZ() } +func (u *updateElectra) Proto() proto.Message { + return u.p +} + func (u *updateElectra) Version() int { return version.Electra } @@ -384,30 +548,72 @@ func (u *updateElectra) AttestedHeader() interfaces.LightClientHeader { return u.attestedHeader } +func (u *updateElectra) SetAttestedHeader(header interfaces.LightClientHeader) { + u.attestedHeader = header +} + func (u *updateElectra) NextSyncCommittee() *pb.SyncCommittee { return u.p.NextSyncCommittee } +func (u *updateElectra) SetNextSyncCommittee(sc *pb.SyncCommittee) { + u.p.NextSyncCommittee = sc +} + func (u *updateElectra) NextSyncCommitteeBranch() (interfaces.LightClientSyncCommitteeBranch, error) { return [5][32]byte{}, consensustypes.ErrNotSupported("NextSyncCommitteeBranch", version.Electra) } +func (u *updateElectra) SetNextSyncCommitteeBranch([][]byte) error { + return consensustypes.ErrNotSupported("SetNextSyncCommitteeBranch", version.Electra) +} + func (u *updateElectra) NextSyncCommitteeBranchElectra() (interfaces.LightClientSyncCommitteeBranchElectra, error) { return u.nextSyncCommitteeBranch, nil } +func (u *updateElectra) SetNextSyncCommitteeBranchElectra(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientSyncCommitteeBranchElectra]("sync committee", branch, fieldparams.SyncCommitteeBranchDepthElectra) + if err != nil { + return err + } + u.nextSyncCommitteeBranch = b + return nil +} + func (u *updateElectra) FinalizedHeader() interfaces.LightClientHeader { return u.finalizedHeader } +func (u *updateElectra) SetFinalizedHeader(header interfaces.LightClientHeader) { + u.finalizedHeader = header +} + func (u *updateElectra) FinalityBranch() interfaces.LightClientFinalityBranch { return u.finalityBranch } +func (u *updateElectra) SetFinalityBranch(branch [][]byte) error { + b, err := createBranch[interfaces.LightClientFinalityBranch]("finality", branch, fieldparams.FinalityBranchDepth) + if err != nil { + return err + } + u.finalityBranch = b + return nil +} + func (u *updateElectra) SyncAggregate() *pb.SyncAggregate { return u.p.SyncAggregate } +func (u *updateElectra) SetSyncAggregate(sa *pb.SyncAggregate) { + u.p.SyncAggregate = sa +} + func (u *updateElectra) SignatureSlot() primitives.Slot { return u.p.SignatureSlot } + +func (u *updateElectra) SetSignatureSlot(slot primitives.Slot) { + u.p.SignatureSlot = slot +}