package structs import ( "encoding/json" "fmt" "github.com/OffchainLabs/prysm/v7/consensus-types/interfaces" enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1" "github.com/OffchainLabs/prysm/v7/runtime/version" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" ) 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 := lightClientHeaderToJSON(update.FinalizedHeader()) if err != nil { return nil, errors.Wrap(err, "could not marshal finalized light client header") } var scBranch [][32]byte var finalityBranch [][32]byte if update.Version() >= version.Electra { scb, err := update.NextSyncCommitteeBranchElectra() if err != nil { return nil, err } scBranch = scb[:] fb, err := update.FinalityBranchElectra() if err != nil { return nil, err } finalityBranch = fb[:] } else { scb, err := update.NextSyncCommitteeBranch() if err != nil { return nil, err } scBranch = scb[:] fb, err := update.FinalityBranch() if err != nil { return nil, err } finalityBranch = fb[:] } return &LightClientUpdate{ AttestedHeader: attestedHeader, NextSyncCommittee: SyncCommitteeFromConsensus(update.NextSyncCommittee()), NextSyncCommitteeBranch: branchToJSON(scBranch), FinalizedHeader: finalizedHeader, FinalityBranch: branchToJSON(finalityBranch), SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()), SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()), }, nil } 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 := lightClientHeaderToJSON(update.FinalizedHeader()) if err != nil { return nil, errors.Wrap(err, "could not marshal finalized light client header") } var finalityBranch [][32]byte if update.Version() >= version.Electra { b, err := update.FinalityBranchElectra() if err != nil { return nil, err } finalityBranch = b[:] } else { b, err := update.FinalityBranch() if err != nil { return nil, err } finalityBranch = b[:] } return &LightClientFinalityUpdate{ AttestedHeader: attestedHeader, FinalizedHeader: finalizedHeader, FinalityBranch: branchToJSON(finalityBranch), SyncAggregate: SyncAggregateFromConsensus(update.SyncAggregate()), SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()), }, nil } 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: SyncAggregateFromConsensus(update.SyncAggregate()), SignatureSlot: fmt.Sprintf("%d", update.SignatureSlot()), }, nil } 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[:]) } return branch } func lightClientHeaderToJSON(header interfaces.LightClientHeader) (json.RawMessage, error) { // In the case that a finalizedHeader is nil. if header == nil { return nil, nil } var result any 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 } 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(executionBranch[:]), } case version.Deneb: exInterface, err := header.Execution() if err != nil { return nil, err } ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderDeneb) if !ok { return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderDeneb{}) } execution, err := ExecutionPayloadHeaderDenebFromConsensus(ex) if err != nil { return nil, err } executionBranch, err := header.ExecutionBranch() if err != nil { return nil, err } result = &LightClientHeaderDeneb{ Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()), Execution: execution, ExecutionBranch: branchToJSON(executionBranch[:]), } case version.Electra: exInterface, err := header.Execution() if err != nil { return nil, err } ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderDeneb) if !ok { return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderDeneb{}) } execution, err := ExecutionPayloadHeaderElectraFromConsensus(ex) if err != nil { return nil, err } executionBranch, err := header.ExecutionBranch() if err != nil { return nil, err } result = &LightClientHeaderDeneb{ Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()), Execution: execution, ExecutionBranch: branchToJSON(executionBranch[:]), } default: return nil, fmt.Errorf("unsupported header version %s", version.String(v)) } return json.Marshal(result) } func LightClientBootstrapFromConsensus(bootstrap interfaces.LightClientBootstrap) (*LightClientBootstrap, error) { header, err := lightClientHeaderToJSON(bootstrap.Header()) if err != nil { return nil, errors.Wrap(err, "could not marshal light client header") } var scBranch [][32]byte if bootstrap.Version() >= version.Electra { b, err := bootstrap.CurrentSyncCommitteeBranchElectra() if err != nil { return nil, err } scBranch = b[:] } else { b, err := bootstrap.CurrentSyncCommitteeBranch() if err != nil { return nil, err } scBranch = b[:] } return &LightClientBootstrap{ Header: header, CurrentSyncCommittee: SyncCommitteeFromConsensus(bootstrap.CurrentSyncCommittee()), CurrentSyncCommitteeBranch: branchToJSON(scBranch), }, nil }