From 3f5c83c6f6a3143b4d487eed0af07d26d06ffb1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isabel=20Sch=C3=B6ps=20Thiel?= <155141998+IST-Github@users.noreply.github.com> Date: Mon, 1 Jan 2024 00:35:15 +0100 Subject: [PATCH] Delete beacon/types directory --- beacon/types/committee.go | 191 ------------------------- beacon/types/config.go | 176 ----------------------- beacon/types/gen_header_json.go | 66 --------- beacon/types/gen_syncaggregate_json.go | 51 ------- beacon/types/header.go | 121 ---------------- beacon/types/light_sync.go | 136 ------------------ 6 files changed, 741 deletions(-) delete mode 100644 beacon/types/committee.go delete mode 100644 beacon/types/config.go delete mode 100644 beacon/types/gen_header_json.go delete mode 100644 beacon/types/gen_syncaggregate_json.go delete mode 100644 beacon/types/header.go delete mode 100644 beacon/types/light_sync.go diff --git a/beacon/types/committee.go b/beacon/types/committee.go deleted file mode 100644 index 5f89c27554..0000000000 --- a/beacon/types/committee.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package types - -import ( - "crypto/sha256" - "encoding/json" - "fmt" - "math/bits" - - "github.com/ethereum/go-ethereum/beacon/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - bls "github.com/protolambda/bls12-381-util" -) - -// SerializedSyncCommitteeSize is the size of the sync committee plus the -// aggregate public key. -const SerializedSyncCommitteeSize = (params.SyncCommitteeSize + 1) * params.BLSPubkeySize - -// SerializedSyncCommittee is the serialized version of a sync committee -// plus the aggregate public key. -type SerializedSyncCommittee [SerializedSyncCommitteeSize]byte - -// jsonSyncCommittee is the JSON representation of a sync committee. -// -// See data structure definition here: -// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate -type jsonSyncCommittee struct { - Pubkeys []hexutil.Bytes `json:"pubkeys"` - Aggregate hexutil.Bytes `json:"aggregate_pubkey"` -} - -// MarshalJSON implements json.Marshaler. -func (s *SerializedSyncCommittee) MarshalJSON() ([]byte, error) { - sc := jsonSyncCommittee{Pubkeys: make([]hexutil.Bytes, params.SyncCommitteeSize)} - for i := range sc.Pubkeys { - sc.Pubkeys[i] = make(hexutil.Bytes, params.BLSPubkeySize) - copy(sc.Pubkeys[i][:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize]) - } - sc.Aggregate = make(hexutil.Bytes, params.BLSPubkeySize) - copy(sc.Aggregate[:], s[params.SyncCommitteeSize*params.BLSPubkeySize:]) - return json.Marshal(&sc) -} - -// UnmarshalJSON implements json.Marshaler. -func (s *SerializedSyncCommittee) UnmarshalJSON(input []byte) error { - var sc jsonSyncCommittee - if err := json.Unmarshal(input, &sc); err != nil { - return err - } - if len(sc.Pubkeys) != params.SyncCommitteeSize { - return fmt.Errorf("invalid number of pubkeys %d", len(sc.Pubkeys)) - } - for i, key := range sc.Pubkeys { - if len(key) != params.BLSPubkeySize { - return fmt.Errorf("pubkey %d has invalid size %d", i, len(key)) - } - copy(s[i*params.BLSPubkeySize:], key[:]) - } - if len(sc.Aggregate) != params.BLSPubkeySize { - return fmt.Errorf("invalid aggregate pubkey size %d", len(sc.Aggregate)) - } - copy(s[params.SyncCommitteeSize*params.BLSPubkeySize:], sc.Aggregate[:]) - return nil -} - -// Root calculates the root hash of the binary tree representation of a sync -// committee provided in serialized format. -// -// TODO(zsfelfoldi): Get rid of this when SSZ encoding lands. -func (s *SerializedSyncCommittee) Root() common.Hash { - var ( - hasher = sha256.New() - padding [64 - params.BLSPubkeySize]byte - data [params.SyncCommitteeSize]common.Hash - l = params.SyncCommitteeSize - ) - for i := range data { - hasher.Reset() - hasher.Write(s[i*params.BLSPubkeySize : (i+1)*params.BLSPubkeySize]) - hasher.Write(padding[:]) - hasher.Sum(data[i][:0]) - } - for l > 1 { - for i := 0; i < l/2; i++ { - hasher.Reset() - hasher.Write(data[i*2][:]) - hasher.Write(data[i*2+1][:]) - hasher.Sum(data[i][:0]) - } - l /= 2 - } - hasher.Reset() - hasher.Write(s[SerializedSyncCommitteeSize-params.BLSPubkeySize : SerializedSyncCommitteeSize]) - hasher.Write(padding[:]) - hasher.Sum(data[1][:0]) - hasher.Reset() - hasher.Write(data[0][:]) - hasher.Write(data[1][:]) - hasher.Sum(data[0][:0]) - return data[0] -} - -// Deserialize splits open the pubkeys into proper BLS key types. -func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) { - sc := new(SyncCommittee) - for i := 0; i <= params.SyncCommitteeSize; i++ { - key := new(bls.Pubkey) - - var bytes [params.BLSPubkeySize]byte - copy(bytes[:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize]) - - if err := key.Deserialize(&bytes); err != nil { - return nil, err - } - if i < params.SyncCommitteeSize { - sc.keys[i] = key - } else { - sc.aggregate = key - } - } - return sc, nil -} - -// SyncCommittee is a set of sync committee signer pubkeys and the aggregate key. -// -// See data structure definition here: -// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate -type SyncCommittee struct { - keys [params.SyncCommitteeSize]*bls.Pubkey - aggregate *bls.Pubkey -} - -// VerifySignature returns true if the given sync aggregate is a valid signature -// or the given hash. -func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *SyncAggregate) bool { - var ( - sig bls.Signature - keys = make([]*bls.Pubkey, 0, params.SyncCommitteeSize) - ) - if err := sig.Deserialize(&signature.Signature); err != nil { - return false - } - for i, key := range sc.keys { - if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 { - keys = append(keys, key) - } - } - return bls.FastAggregateVerify(keys, signingRoot[:], &sig) -} - -//go:generate go run github.com/fjl/gencodec -type SyncAggregate -field-override syncAggregateMarshaling -out gen_syncaggregate_json.go - -// SyncAggregate represents an aggregated BLS signature with Signers referring -// to a subset of the corresponding sync committee. -// -// See data structure definition here: -// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate -type SyncAggregate struct { - Signers [params.SyncCommitteeBitmaskSize]byte `gencodec:"required" json:"sync_committee_bits"` - Signature [params.BLSSignatureSize]byte `gencodec:"required" json:"sync_committee_signature"` -} - -type syncAggregateMarshaling struct { - Signers hexutil.Bytes - Signature hexutil.Bytes -} - -// SignerCount returns the number of signers in the aggregate signature. -func (s *SyncAggregate) SignerCount() int { - var count int - for _, v := range s.Signers { - count += bits.OnesCount8(v) - } - return count -} diff --git a/beacon/types/config.go b/beacon/types/config.go deleted file mode 100644 index 8cb8808b6f..0000000000 --- a/beacon/types/config.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package types - -import ( - "crypto/sha256" - "fmt" - "os" - "sort" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/beacon/merkle" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "gopkg.in/yaml.v3" -) - -// syncCommitteeDomain specifies the signatures specific use to avoid clashes -// across signing different data structures. -const syncCommitteeDomain = 7 - -// Fork describes a single beacon chain fork and also stores the calculated -// signature domain used after this fork. -type Fork struct { - // Name of the fork in the chain config (config.yaml) file{ - Name string - - // Epoch when given fork version is activated - Epoch uint64 - - // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types - Version []byte - - // calculated by computeDomain, based on fork version and genesis validators root - domain merkle.Value -} - -// computeDomain returns the signature domain based on the given fork version -// and genesis validator set root. -func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) { - var ( - hasher = sha256.New() - forkVersion32 merkle.Value - forkDataRoot merkle.Value - ) - copy(forkVersion32[:], f.Version) - hasher.Write(forkVersion32[:]) - hasher.Write(genesisValidatorsRoot[:]) - hasher.Sum(forkDataRoot[:0]) - - f.domain[0] = syncCommitteeDomain - copy(f.domain[4:], forkDataRoot[:28]) -} - -// Forks is the list of all beacon chain forks in the chain configuration. -type Forks []*Fork - -// domain returns the signature domain for the given epoch (assumes that domains -// have already been calculated). -func (f Forks) domain(epoch uint64) (merkle.Value, error) { - for i := len(f) - 1; i >= 0; i-- { - if epoch >= f[i].Epoch { - return f[i].domain, nil - } - } - return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch) -} - -// SigningRoot calculates the signing root of the given header. -func (f Forks) SigningRoot(header Header) (common.Hash, error) { - domain, err := f.domain(header.Epoch()) - if err != nil { - return common.Hash{}, err - } - var ( - signingRoot common.Hash - headerHash = header.Hash() - hasher = sha256.New() - ) - hasher.Write(headerHash[:]) - hasher.Write(domain[:]) - hasher.Sum(signingRoot[:0]) - - return signingRoot, nil -} - -func (f Forks) Len() int { return len(f) } -func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] } -func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch } - -// ChainConfig contains the beacon chain configuration. -type ChainConfig struct { - GenesisTime uint64 // Unix timestamp of slot 0 - GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation - Forks Forks -} - -// AddFork adds a new item to the list of forks. -func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig { - fork := &Fork{ - Name: name, - Epoch: epoch, - Version: version, - } - fork.computeDomain(c.GenesisValidatorsRoot) - - c.Forks = append(c.Forks, fork) - sort.Sort(c.Forks) - - return c -} - -// LoadForks parses the beacon chain configuration file (config.yaml) and extracts -// the list of forks. -func (c *ChainConfig) LoadForks(path string) error { - file, err := os.ReadFile(path) - if err != nil { - return fmt.Errorf("failed to read beacon chain config file: %v", err) - } - config := make(map[string]string) - if err := yaml.Unmarshal(file, &config); err != nil { - return fmt.Errorf("failed to parse beacon chain config file: %v", err) - } - var ( - versions = make(map[string][]byte) - epochs = make(map[string]uint64) - ) - epochs["GENESIS"] = 0 - - for key, value := range config { - if strings.HasSuffix(key, "_FORK_VERSION") { - name := key[:len(key)-len("_FORK_VERSION")] - if v, err := hexutil.Decode(value); err == nil { - versions[name] = v - } else { - return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err) - } - } - if strings.HasSuffix(key, "_FORK_EPOCH") { - name := key[:len(key)-len("_FORK_EPOCH")] - if v, err := strconv.ParseUint(value, 10, 64); err == nil { - epochs[name] = v - } else { - return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err) - } - } - } - for name, epoch := range epochs { - if version, ok := versions[name]; ok { - delete(versions, name) - c.AddFork(name, epoch, version) - } else { - return fmt.Errorf("fork id missing for %q in beacon chain config file", name) - } - } - for name := range versions { - return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name) - } - sort.Sort(c.Forks) - return nil -} diff --git a/beacon/types/gen_header_json.go b/beacon/types/gen_header_json.go deleted file mode 100644 index 9b3ffea06f..0000000000 --- a/beacon/types/gen_header_json.go +++ /dev/null @@ -1,66 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package types - -import ( - "encoding/json" - "errors" - - "github.com/ethereum/go-ethereum/common" -) - -var _ = (*headerMarshaling)(nil) - -// MarshalJSON marshals as JSON. -func (h Header) MarshalJSON() ([]byte, error) { - type Header struct { - Slot common.Decimal `gencodec:"required" json:"slot"` - ProposerIndex common.Decimal `gencodec:"required" json:"proposer_index"` - ParentRoot common.Hash `gencodec:"required" json:"parent_root"` - StateRoot common.Hash `gencodec:"required" json:"state_root"` - BodyRoot common.Hash `gencodec:"required" json:"body_root"` - } - var enc Header - enc.Slot = common.Decimal(h.Slot) - enc.ProposerIndex = common.Decimal(h.ProposerIndex) - enc.ParentRoot = h.ParentRoot - enc.StateRoot = h.StateRoot - enc.BodyRoot = h.BodyRoot - return json.Marshal(&enc) -} - -// UnmarshalJSON unmarshals from JSON. -func (h *Header) UnmarshalJSON(input []byte) error { - type Header struct { - Slot *common.Decimal `gencodec:"required" json:"slot"` - ProposerIndex *common.Decimal `gencodec:"required" json:"proposer_index"` - ParentRoot *common.Hash `gencodec:"required" json:"parent_root"` - StateRoot *common.Hash `gencodec:"required" json:"state_root"` - BodyRoot *common.Hash `gencodec:"required" json:"body_root"` - } - var dec Header - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.Slot == nil { - return errors.New("missing required field 'slot' for Header") - } - h.Slot = uint64(*dec.Slot) - if dec.ProposerIndex == nil { - return errors.New("missing required field 'proposer_index' for Header") - } - h.ProposerIndex = uint64(*dec.ProposerIndex) - if dec.ParentRoot == nil { - return errors.New("missing required field 'parent_root' for Header") - } - h.ParentRoot = *dec.ParentRoot - if dec.StateRoot == nil { - return errors.New("missing required field 'state_root' for Header") - } - h.StateRoot = *dec.StateRoot - if dec.BodyRoot == nil { - return errors.New("missing required field 'body_root' for Header") - } - h.BodyRoot = *dec.BodyRoot - return nil -} diff --git a/beacon/types/gen_syncaggregate_json.go b/beacon/types/gen_syncaggregate_json.go deleted file mode 100644 index 1547ec5f01..0000000000 --- a/beacon/types/gen_syncaggregate_json.go +++ /dev/null @@ -1,51 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package types - -import ( - "encoding/json" - "errors" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -var _ = (*syncAggregateMarshaling)(nil) - -// MarshalJSON marshals as JSON. -func (s SyncAggregate) MarshalJSON() ([]byte, error) { - type SyncAggregate struct { - Signers hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"` - Signature hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"` - } - var enc SyncAggregate - enc.Signers = s.Signers[:] - enc.Signature = s.Signature[:] - return json.Marshal(&enc) -} - -// UnmarshalJSON unmarshals from JSON. -func (s *SyncAggregate) UnmarshalJSON(input []byte) error { - type SyncAggregate struct { - Signers *hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"` - Signature *hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"` - } - var dec SyncAggregate - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.Signers == nil { - return errors.New("missing required field 'sync_committee_bits' for SyncAggregate") - } - if len(*dec.Signers) != len(s.Signers) { - return errors.New("field 'sync_committee_bits' has wrong length, need 64 items") - } - copy(s.Signers[:], *dec.Signers) - if dec.Signature == nil { - return errors.New("missing required field 'sync_committee_signature' for SyncAggregate") - } - if len(*dec.Signature) != len(s.Signature) { - return errors.New("field 'sync_committee_signature' has wrong length, need 96 items") - } - copy(s.Signature[:], *dec.Signature) - return nil -} diff --git a/beacon/types/header.go b/beacon/types/header.go deleted file mode 100644 index 2ddc4575f1..0000000000 --- a/beacon/types/header.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package types implements a few types of the beacon chain for light client usage. -package types - -import ( - "crypto/sha256" - "encoding/binary" - - "github.com/ethereum/go-ethereum/beacon/merkle" - "github.com/ethereum/go-ethereum/beacon/params" - "github.com/ethereum/go-ethereum/common" -) - -//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go - -const ( - headerIndexSlot = 8 - headerIndexProposerIndex = 9 - headerIndexParentRoot = 10 - headerIndexStateRoot = 11 - headerIndexBodyRoot = 12 -) - -// Header defines a beacon header. -// -// See data structure definition here: -// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader -type Header struct { - // Monotonically increasing slot number for the beacon block (may be gapped) - Slot uint64 `gencodec:"required" json:"slot"` - - // Index into the validator table who created the beacon block - ProposerIndex uint64 `gencodec:"required" json:"proposer_index"` - - // SSZ hash of the parent beacon header - ParentRoot common.Hash `gencodec:"required" json:"parent_root"` - - // SSZ hash of the beacon state (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beacon-state) - StateRoot common.Hash `gencodec:"required" json:"state_root"` - - // SSZ hash of the beacon block body (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beaconblockbody) - BodyRoot common.Hash `gencodec:"required" json:"body_root"` -} - -// headerMarshaling is a field type overrides for gencodec. -type headerMarshaling struct { - Slot common.Decimal - ProposerIndex common.Decimal -} - -// Hash calculates the block root of the header. -// -// TODO(zsfelfoldi): Remove this when an SSZ encoder lands. -func (h *Header) Hash() common.Hash { - var values [16]merkle.Value // values corresponding to indices 8 to 15 of the beacon header tree - binary.LittleEndian.PutUint64(values[headerIndexSlot][:8], h.Slot) - binary.LittleEndian.PutUint64(values[headerIndexProposerIndex][:8], h.ProposerIndex) - values[headerIndexParentRoot] = merkle.Value(h.ParentRoot) - values[headerIndexStateRoot] = merkle.Value(h.StateRoot) - values[headerIndexBodyRoot] = merkle.Value(h.BodyRoot) - hasher := sha256.New() - for i := 7; i > 0; i-- { - hasher.Reset() - hasher.Write(values[i*2][:]) - hasher.Write(values[i*2+1][:]) - hasher.Sum(values[i][:0]) - } - return common.Hash(values[1]) -} - -// Epoch returns the epoch the header belongs to. -func (h *Header) Epoch() uint64 { - return h.Slot / params.EpochLength -} - -// SyncPeriod returns the sync period the header belongs to. -func (h *Header) SyncPeriod() uint64 { - return SyncPeriod(h.Slot) -} - -// SyncPeriodStart returns the first slot of the given period. -func SyncPeriodStart(period uint64) uint64 { - return period * params.SyncPeriodLength -} - -// SyncPeriod returns the sync period that the given slot belongs to. -func SyncPeriod(slot uint64) uint64 { - return slot / params.SyncPeriodLength -} - -// SignedHeader represents a beacon header signed by a sync committee. -// -// This structure is created from either an optimistic update or an instant update: -// - https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate -// - https://github.com/zsfelfoldi/beacon-APIs/blob/instant_update/apis/beacon/light_client/instant_update.yaml -type SignedHeader struct { - // Beacon header being signed - Header Header - - // Sync committee BLS signature aggregate - Signature SyncAggregate - - // Slot in which the signature has been created (newer than Header.Slot, - // determines the signing sync committee) - SignatureSlot uint64 -} diff --git a/beacon/types/light_sync.go b/beacon/types/light_sync.go deleted file mode 100644 index 3284081e4d..0000000000 --- a/beacon/types/light_sync.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package types - -import ( - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/beacon/merkle" - "github.com/ethereum/go-ethereum/beacon/params" - "github.com/ethereum/go-ethereum/common" -) - -// BootstrapData contains a sync committee where light sync can be started, -// together with a proof through a beacon header and corresponding state. -// Note: BootstrapData is fetched from a server based on a known checkpoint hash. -type BootstrapData struct { - Header Header - CommitteeRoot common.Hash - Committee *SerializedSyncCommittee `rlp:"-"` - CommitteeBranch merkle.Values -} - -// Validate verifies the proof included in BootstrapData. -func (c *BootstrapData) Validate() error { - if c.CommitteeRoot != c.Committee.Root() { - return errors.New("wrong committee root") - } - return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee, c.CommitteeBranch, merkle.Value(c.CommitteeRoot)) -} - -// LightClientUpdate is a proof of the next sync committee root based on a header -// signed by the sync committee of the given period. Optionally, the update can -// prove quasi-finality by the signed header referring to a previous, finalized -// header from the same period, and the finalized header referring to the next -// sync committee root. -// -// See data structure definition here: -// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate -type LightClientUpdate struct { - 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 - NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee - - FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality - FinalityBranch merkle.Values // Proof for the announced finality - - score *UpdateScore // Weight of the update to compare between competing ones -} - -// Validate verifies the validity of the update. -func (update *LightClientUpdate) Validate() error { - period := update.AttestedHeader.Header.SyncPeriod() - if SyncPeriod(update.AttestedHeader.SignatureSlot) != period { - return errors.New("signature slot and signed header are from different periods") - } - if update.FinalizedHeader != nil { - if update.FinalizedHeader.SyncPeriod() != 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 { - 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 { - return fmt.Errorf("invalid next sync committee proof: %w", err) - } - return nil -} - -// Score returns the UpdateScore describing the proof strength of the update -// Note: thread safety can be ensured by always calling Score on a newly received -// or decoded update before making it potentially available for other threads -func (update *LightClientUpdate) Score() UpdateScore { - if update.score == nil { - update.score = &UpdateScore{ - SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()), - SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff), - FinalizedHeader: update.FinalizedHeader != nil, - } - } - return *update.score -} - -// UpdateScore allows the comparison between updates at the same period in order -// to find the best update chain that provides the strongest proof of being canonical. -// -// UpdateScores have a tightly packed binary encoding format for efficient p2p -// protocol transmission. Each UpdateScore is encoded in 3 bytes. -// When interpreted as a 24 bit little indian unsigned integer: -// - the lowest 10 bits contain the number of signers in the header signature aggregate -// - the next 13 bits contain the "sub-period index" which is he signed header's -// slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being -// re-orged before the previous period boundary in case of non-finalized updates) -// - the highest bit is set when the update is finalized (meaning that the finality -// header referenced by the signed header is in the same period as the signed -// header, making reorgs before the period boundary impossible -type UpdateScore struct { - SignerCount uint32 // number of signers in the header signature aggregate - SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength - FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures -} - -// finalized returns true if the update has a header signed by at least 2/3 of -// the committee, referring to a finalized header that refers to the next sync -// committee. This condition is a close approximation of the actual finality -// condition that can only be verified by full beacon nodes. -func (u *UpdateScore) finalized() bool { - return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority -} - -// BetterThan returns true if update u is considered better than w. -func (u UpdateScore) BetterThan(w UpdateScore) bool { - var ( - uFinalized = u.finalized() - wFinalized = w.finalized() - ) - if uFinalized != wFinalized { - return uFinalized - } - return u.SignerCount > w.SignerCount -}