save light client updates (diff) (#14683)

* update diff

* deps

* add tests for `SaveLightClientUpdate`

* cleanup imports

* lint

* changelog

* fix incorrect arithmetic

* check for lightclient feature flag

* fix tests

* fix `saveLightClientBootstrap` and `saveLightClientUpdate`

* replace and with or

* move feature check to `postBlockProcess`

---------

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

View File

@@ -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",

View File

@@ -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),
}
}

View File

@@ -3,125 +3,227 @@ 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")
}
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(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")
}
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(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 result any
var header any
switch t := (container.Header).(type) {
case *v2.LightClientHeaderContainer_HeaderAltair:
header = &LightClientHeader{Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon))}
case *v2.LightClientHeaderContainer_HeaderCapella:
execution, err := ExecutionPayloadHeaderCapellaFromConsensus(t.HeaderCapella.Execution)
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)),
Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderCapella.ExecutionBranch),
ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderCapella)
if !ok {
return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderCapella{})
}
case *v2.LightClientHeaderContainer_HeaderDeneb:
execution, err := ExecutionPayloadHeaderDenebFromConsensus(t.HeaderDeneb.Execution)
execution, err := ExecutionPayloadHeaderCapellaFromConsensus(ex)
if err != nil {
return nil, err
}
header = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)),
executionBranch, err := header.ExecutionBranch()
if err != nil {
return nil, err
}
result = &LightClientHeaderCapella{
Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()),
Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderDeneb.ExecutionBranch),
ExecutionBranch: branchToJSON(executionBranch[:]),
}
case version.Deneb:
exInterface, err := header.Execution()
if err != nil {
return nil, err
}
ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderDeneb)
if !ok {
return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderDeneb{})
}
execution, err := ExecutionPayloadHeaderDenebFromConsensus(ex)
if err != nil {
return nil, err
}
executionBranch, err := header.ExecutionBranch()
if err != nil {
return nil, err
}
result = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()),
Execution: execution,
ExecutionBranch: branchToJSON(executionBranch[:]),
}
case version.Electra:
exInterface, err := header.Execution()
if err != nil {
return nil, err
}
ex, ok := exInterface.Proto().(*enginev1.ExecutionPayloadHeaderElectra)
if !ok {
return nil, fmt.Errorf("execution data is not %T", &enginev1.ExecutionPayloadHeaderElectra{})
}
execution, err := ExecutionPayloadHeaderElectraFromConsensus(ex)
if err != nil {
return nil, err
}
executionBranch, err := header.ExecutionBranch()
if err != nil {
return nil, err
}
result = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(header.Beacon()),
Execution: execution,
ExecutionBranch: branchToJSON(executionBranch[:]),
}
default:
return nil, fmt.Errorf("unsupported header type %T", t)
return nil, fmt.Errorf("unsupported header version %s", version.String(v))
}
return json.Marshal(header)
return json.Marshal(result)
}
func LightClientBootstrapFromConsensus(bootstrap interfaces.LightClientBootstrap) (*LightClientBootstrap, error) {
header, err := lightClientHeaderToJSON(bootstrap.Header())
if err != nil {
return nil, errors.Wrap(err, "could not marshal light client header")
}
var scBranch [][32]byte
if bootstrap.Version() >= version.Electra {
b, err := bootstrap.CurrentSyncCommitteeBranchElectra()
if err != nil {
return nil, err
}
scBranch = b[:]
} else {
b, err := bootstrap.CurrentSyncCommitteeBranch()
if err != nil {
return nil, err
}
scBranch = b[:]
}
return &LightClientBootstrap{
Header: header,
CurrentSyncCommittee: SyncCommitteeFromConsensus(bootstrap.CurrentSyncCommittee()),
CurrentSyncCommitteeBranch: branchToJSON(scBranch),
}, nil
}