beacon: fixed issues with electra light sync

This commit is contained in:
Zsolt Felfoldi 2025-03-11 16:50:13 +01:00 committed by Felix Lange
parent 4da69b3782
commit f8b07baee2
7 changed files with 65 additions and 29 deletions

View file

@ -140,7 +140,7 @@ func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHead
var method string var method string
switch fork { switch fork {
case "deneb": case "deneb", "electra":
method = "engine_forkchoiceUpdatedV3" method = "engine_forkchoiceUpdatedV3"
case "capella": case "capella":
method = "engine_forkchoiceUpdatedV2" method = "engine_forkchoiceUpdatedV2"

View file

@ -43,7 +43,6 @@ var (
) )
type CommitteeUpdate struct { type CommitteeUpdate struct {
Version string
Update types.LightClientUpdate Update types.LightClientUpdate
NextSyncCommittee types.SerializedSyncCommittee NextSyncCommittee types.SerializedSyncCommittee
} }
@ -81,9 +80,9 @@ func (u *CommitteeUpdate) UnmarshalJSON(input []byte) error {
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
u.Version = dec.Version
u.NextSyncCommittee = dec.Data.NextSyncCommittee u.NextSyncCommittee = dec.Data.NextSyncCommittee
u.Update = types.LightClientUpdate{ u.Update = types.LightClientUpdate{
Version: dec.Version,
AttestedHeader: types.SignedHeader{ AttestedHeader: types.SignedHeader{
Header: dec.Data.Header.Beacon, Header: dec.Data.Header.Beacon,
Signature: dec.Data.SyncAggregate, Signature: dec.Data.SyncAggregate,
@ -206,7 +205,7 @@ func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error)
func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) { func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) {
var data struct { var data struct {
Version string Version string `json:"version"`
Data struct { Data struct {
Attested jsonHeaderWithExecProof `json:"attested_header"` Attested jsonHeaderWithExecProof `json:"attested_header"`
Aggregate types.SyncAggregate `json:"sync_aggregate"` Aggregate types.SyncAggregate `json:"sync_aggregate"`
@ -259,7 +258,7 @@ func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) {
var data struct { var data struct {
Version string Version string `json:"version"`
Data struct { Data struct {
Attested jsonHeaderWithExecProof `json:"attested_header"` Attested jsonHeaderWithExecProof `json:"attested_header"`
Finalized jsonHeaderWithExecProof `json:"finalized_header"` Finalized jsonHeaderWithExecProof `json:"finalized_header"`
@ -289,6 +288,7 @@ func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) {
} }
return types.FinalityUpdate{ return types.FinalityUpdate{
Version: data.Version,
Attested: types.HeaderWithExecProof{ Attested: types.HeaderWithExecProof{
Header: data.Data.Attested.Beacon, Header: data.Data.Attested.Beacon,
PayloadHeader: attestedExecHeader, PayloadHeader: attestedExecHeader,
@ -355,6 +355,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types
// See data structure definition here: // See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientbootstrap // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientbootstrap
type bootstrapData struct { type bootstrapData struct {
Version string `json:"version"`
Data struct { Data struct {
Header jsonBeaconHeader `json:"header"` Header jsonBeaconHeader `json:"header"`
Committee *types.SerializedSyncCommittee `json:"current_sync_committee"` Committee *types.SerializedSyncCommittee `json:"current_sync_committee"`
@ -374,6 +375,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types
return nil, fmt.Errorf("invalid checkpoint block header, have %v want %v", header.Hash(), checkpointHash) return nil, fmt.Errorf("invalid checkpoint block header, have %v want %v", header.Hash(), checkpointHash)
} }
checkpoint := &types.BootstrapData{ checkpoint := &types.BootstrapData{
Version: data.Version,
Header: header, Header: header,
CommitteeBranch: data.Data.CommitteeBranch, CommitteeBranch: data.Data.CommitteeBranch,
CommitteeRoot: data.Data.Committee.Root(), CommitteeRoot: data.Data.Committee.Root(),
@ -395,7 +397,7 @@ func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconB
} }
var beaconBlockMessage struct { var beaconBlockMessage struct {
Version string Version string `json:"version"`
Data struct { Data struct {
Message json.RawMessage `json:"message"` Message json.RawMessage `json:"message"`
} }

View file

@ -39,10 +39,10 @@ func GenerateTestUpdate(config *params.ChainConfig, period uint64, committee, ne
var attestedHeader types.Header var attestedHeader types.Header
if finalizedHeader { if finalizedHeader {
update.FinalizedHeader = new(types.Header) update.FinalizedHeader = new(types.Header)
*update.FinalizedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+100, params.StateIndexNextSyncCommittee, merkle.Value(update.NextSyncCommitteeRoot)) *update.FinalizedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+100, params.StateIndexNextSyncCommittee(""), merkle.Value(update.NextSyncCommitteeRoot))
attestedHeader, update.FinalityBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexFinalBlock, merkle.Value(update.FinalizedHeader.Hash())) attestedHeader, update.FinalityBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexFinalBlock(""), merkle.Value(update.FinalizedHeader.Hash()))
} else { } else {
attestedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+2000, params.StateIndexNextSyncCommittee, merkle.Value(update.NextSyncCommitteeRoot)) attestedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+2000, params.StateIndexNextSyncCommittee(""), merkle.Value(update.NextSyncCommitteeRoot))
} }
update.AttestedHeader = GenerateTestSignedHeader(attestedHeader, config, committee, attestedHeader.Slot+1, signerCount) update.AttestedHeader = GenerateTestSignedHeader(attestedHeader, config, committee, attestedHeader.Slot+1, signerCount)
return update return update
@ -63,7 +63,7 @@ func GenerateTestSignedHeader(header types.Header, config *params.ChainConfig, c
} }
func GenerateTestCheckpoint(period uint64, committee *types.SerializedSyncCommittee) *types.BootstrapData { func GenerateTestCheckpoint(period uint64, committee *types.SerializedSyncCommittee) *types.BootstrapData {
header, branch := makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexSyncCommittee, merkle.Value(committee.Root())) header, branch := makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexSyncCommittee(""), merkle.Value(committee.Root()))
return &types.BootstrapData{ return &types.BootstrapData{
Header: header, Header: header,
Committee: committee, Committee: committee,

View file

@ -41,7 +41,8 @@ var (
AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}). AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}). AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}). AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}) AddFork("DENEB", 132608, []byte{144, 0, 0, 115}).
AddFork("ELECTRA", 222464, []byte{144, 0, 0, 116})
HoleskyLightConfig = (&ChainConfig{ HoleskyLightConfig = (&ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"), GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
@ -52,5 +53,6 @@ var (
AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}). AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}).
AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}). AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}).
AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}). AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}).
AddFork("DENEB", 29696, []byte{5, 1, 112, 0}) AddFork("DENEB", 29696, []byte{5, 1, 112, 0}).
AddFork("ELECTRA", 115968, []byte{6, 1, 112, 0})
) )

View file

@ -36,11 +36,39 @@ const (
StateIndexBlockRoots = 37 StateIndexBlockRoots = 37
StateIndexStateRoots = 38 StateIndexStateRoots = 38
StateIndexHistoricRoots = 39 StateIndexHistoricRoots = 39
StateIndexFinalBlock = 105 StateIndexFinalBlockOld = 105
StateIndexSyncCommittee = 54 StateIndexFinalBlockElectra = 169
StateIndexNextSyncCommittee = 55 StateIndexSyncCommitteeOld = 54
StateIndexSyncCommitteeElectra = 86
StateIndexNextSyncCommitteeOld = 55
StateIndexNextSyncCommitteeElectra = 87
StateIndexExecPayload = 56 StateIndexExecPayload = 56
StateIndexExecHead = 908 StateIndexExecHead = 908
BodyIndexExecPayload = 25 BodyIndexExecPayload = 25
) )
func StateIndexFinalBlock(forkName string) uint64 {
switch forkName {
case "bellatrix", "capella", "deneb":
return StateIndexFinalBlockOld
default:
return StateIndexFinalBlockElectra
}
}
func StateIndexSyncCommittee(forkName string) uint64 {
switch forkName {
case "bellatrix", "capella", "deneb":
return StateIndexSyncCommitteeOld
default:
return StateIndexSyncCommitteeElectra
}
}
func StateIndexNextSyncCommittee(forkName string) uint64 {
switch forkName {
case "bellatrix", "capella", "deneb":
return StateIndexNextSyncCommitteeOld
default:
return StateIndexNextSyncCommitteeElectra
}
}

View file

@ -144,6 +144,7 @@ func (b *BeaconBlock) ExecutionRequestsList() [][]byte {
func marshalRequests(spec *zrntcommon.Spec, items ...zrntcommon.SpecObj) (list [][]byte) { func marshalRequests(spec *zrntcommon.Spec, items ...zrntcommon.SpecObj) (list [][]byte) {
var buf bytes.Buffer var buf bytes.Buffer
list = [][]byte{}
for typ, data := range items { for typ, data := range items {
buf.Reset() buf.Reset()
buf.WriteByte(byte(typ)) buf.WriteByte(byte(typ))

View file

@ -36,6 +36,7 @@ type HeadInfo struct {
// together with a proof through a beacon header and corresponding state. // together with a proof through a beacon header and corresponding state.
// Note: BootstrapData is fetched from a server based on a known checkpoint hash. // Note: BootstrapData is fetched from a server based on a known checkpoint hash.
type BootstrapData struct { type BootstrapData struct {
Version string
Header Header Header Header
CommitteeRoot common.Hash CommitteeRoot common.Hash
Committee *SerializedSyncCommittee `rlp:"-"` Committee *SerializedSyncCommittee `rlp:"-"`
@ -47,7 +48,7 @@ func (c *BootstrapData) Validate() error {
if c.CommitteeRoot != c.Committee.Root() { if c.CommitteeRoot != c.Committee.Root() {
return errors.New("wrong committee root") return errors.New("wrong committee root")
} }
return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee, c.CommitteeBranch, merkle.Value(c.CommitteeRoot)) return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee(c.Version), c.CommitteeBranch, merkle.Value(c.CommitteeRoot))
} }
// LightClientUpdate is a proof of the next sync committee root based on a header // LightClientUpdate is a proof of the next sync committee root based on a header
@ -59,6 +60,7 @@ func (c *BootstrapData) Validate() error {
// See data structure definition here: // See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
type LightClientUpdate struct { type LightClientUpdate struct {
Version string
AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee
NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one
NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee
@ -79,11 +81,11 @@ func (update *LightClientUpdate) Validate() error {
if update.FinalizedHeader.SyncPeriod() != period { if update.FinalizedHeader.SyncPeriod() != period {
return errors.New("finalized header is from different period") return errors.New("finalized header is from different period")
} }
if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil { if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock(update.Version), update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil {
return fmt.Errorf("invalid finalized header proof: %w", err) return fmt.Errorf("invalid finalized header proof: %w", err)
} }
} }
if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil { if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee(update.Version), update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil {
return fmt.Errorf("invalid next sync committee proof: %w", err) return fmt.Errorf("invalid next sync committee proof: %w", err)
} }
return nil return nil
@ -194,6 +196,7 @@ func (u *OptimisticUpdate) Validate() error {
// See data structure definition here: // See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
type FinalityUpdate struct { type FinalityUpdate struct {
Version string
Attested, Finalized HeaderWithExecProof Attested, Finalized HeaderWithExecProof
FinalityBranch merkle.Values FinalityBranch merkle.Values
// Sync committee BLS signature aggregate // Sync committee BLS signature aggregate
@ -223,7 +226,7 @@ func (u *FinalityUpdate) Validate() error {
if err := u.Finalized.Validate(); err != nil { if err := u.Finalized.Validate(); err != nil {
return err return err
} }
return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock, u.FinalityBranch, merkle.Value(u.Finalized.Hash())) return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock(u.Version), u.FinalityBranch, merkle.Value(u.Finalized.Hash()))
} }
// ChainHeadEvent returns an authenticated execution payload associated with the // ChainHeadEvent returns an authenticated execution payload associated with the