github.com/ethereum/go-ethereum@v1.16.1/beacon/types/light_sync.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  
    23  	"github.com/ethereum/go-ethereum/beacon/merkle"
    24  	"github.com/ethereum/go-ethereum/beacon/params"
    25  	"github.com/ethereum/go-ethereum/common"
    26  	ctypes "github.com/ethereum/go-ethereum/core/types"
    27  )
    28  
    29  // HeadInfo represents an unvalidated new head announcement.
    30  type HeadInfo struct {
    31  	Slot      uint64
    32  	BlockRoot common.Hash
    33  }
    34  
    35  // BootstrapData contains a sync committee where light sync can be started,
    36  // together with a proof through a beacon header and corresponding state.
    37  // Note: BootstrapData is fetched from a server based on a known checkpoint hash.
    38  type BootstrapData struct {
    39  	Version         string
    40  	Header          Header
    41  	CommitteeRoot   common.Hash
    42  	Committee       *SerializedSyncCommittee `rlp:"-"`
    43  	CommitteeBranch merkle.Values
    44  }
    45  
    46  // Validate verifies the proof included in BootstrapData.
    47  func (c *BootstrapData) Validate() error {
    48  	if c.CommitteeRoot != c.Committee.Root() {
    49  		return errors.New("wrong committee root")
    50  	}
    51  	return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee(c.Version), c.CommitteeBranch, merkle.Value(c.CommitteeRoot))
    52  }
    53  
    54  // LightClientUpdate is a proof of the next sync committee root based on a header
    55  // signed by the sync committee of the given period. Optionally, the update can
    56  // prove quasi-finality by the signed header referring to a previous, finalized
    57  // header from the same period, and the finalized header referring to the next
    58  // sync committee root.
    59  //
    60  // See data structure definition here:
    61  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
    62  type LightClientUpdate struct {
    63  	Version                 string
    64  	AttestedHeader          SignedHeader  // Arbitrary header out of the period signed by the sync committee
    65  	NextSyncCommitteeRoot   common.Hash   // Sync committee of the next period advertised in the current one
    66  	NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee
    67  
    68  	FinalizedHeader *Header       `rlp:"nil"` // Optional header to announce a point of finality
    69  	FinalityBranch  merkle.Values // Proof for the announced finality
    70  
    71  	score *UpdateScore // Weight of the update to compare between competing ones
    72  }
    73  
    74  // Validate verifies the validity of the update.
    75  func (update *LightClientUpdate) Validate() error {
    76  	period := update.AttestedHeader.Header.SyncPeriod()
    77  	if SyncPeriod(update.AttestedHeader.SignatureSlot) != period {
    78  		return errors.New("signature slot and signed header are from different periods")
    79  	}
    80  	if update.FinalizedHeader != nil {
    81  		if update.FinalizedHeader.SyncPeriod() != period {
    82  			return errors.New("finalized header is from different period")
    83  		}
    84  		if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock(update.Version), update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil {
    85  			return fmt.Errorf("invalid finalized header proof: %w", err)
    86  		}
    87  	}
    88  	if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee(update.Version), update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil {
    89  		return fmt.Errorf("invalid next sync committee proof: %w", err)
    90  	}
    91  	return nil
    92  }
    93  
    94  // Score returns the UpdateScore describing the proof strength of the update
    95  // Note: thread safety can be ensured by always calling Score on a newly received
    96  // or decoded update before making it potentially available for other threads
    97  func (update *LightClientUpdate) Score() UpdateScore {
    98  	if update.score == nil {
    99  		update.score = &UpdateScore{
   100  			SignerCount:     uint32(update.AttestedHeader.Signature.SignerCount()),
   101  			SubPeriodIndex:  uint32(update.AttestedHeader.Header.Slot & 0x1fff),
   102  			FinalizedHeader: update.FinalizedHeader != nil,
   103  		}
   104  	}
   105  	return *update.score
   106  }
   107  
   108  // UpdateScore allows the comparison between updates at the same period in order
   109  // to find the best update chain that provides the strongest proof of being canonical.
   110  //
   111  // UpdateScores have a tightly packed binary encoding format for efficient p2p
   112  // protocol transmission. Each UpdateScore is encoded in 3 bytes.
   113  // When interpreted as a 24 bit little indian unsigned integer:
   114  //   - the lowest 10 bits contain the number of signers in the header signature aggregate
   115  //   - the next 13 bits contain the "sub-period index" which is he signed header's
   116  //     slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being
   117  //     re-orged before the previous period boundary in case of non-finalized updates)
   118  //   - the highest bit is set when the update is finalized (meaning that the finality
   119  //     header referenced by the signed header is in the same period as the signed
   120  //     header, making reorgs before the period boundary impossible
   121  type UpdateScore struct {
   122  	SignerCount     uint32 // number of signers in the header signature aggregate
   123  	SubPeriodIndex  uint32 // signed header's slot modulo params.SyncPeriodLength
   124  	FinalizedHeader bool   // update is considered finalized if has finalized header from the same period and 2/3 signatures
   125  }
   126  
   127  // finalized returns true if the update has a header signed by at least 2/3 of
   128  // the committee, referring to a finalized header that refers to the next sync
   129  // committee. This condition is a close approximation of the actual finality
   130  // condition that can only be verified by full beacon nodes.
   131  func (u *UpdateScore) finalized() bool {
   132  	return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority
   133  }
   134  
   135  // BetterThan returns true if update u is considered better than w.
   136  func (u UpdateScore) BetterThan(w UpdateScore) bool {
   137  	var (
   138  		uFinalized = u.finalized()
   139  		wFinalized = w.finalized()
   140  	)
   141  	if uFinalized != wFinalized {
   142  		return uFinalized
   143  	}
   144  	return u.SignerCount > w.SignerCount
   145  }
   146  
   147  // HeaderWithExecProof contains a beacon header and proves the belonging execution
   148  // payload header with a Merkle proof.
   149  type HeaderWithExecProof struct {
   150  	Header
   151  	PayloadHeader *ExecutionHeader
   152  	PayloadBranch merkle.Values
   153  }
   154  
   155  // Validate verifies the Merkle proof of the execution payload header.
   156  func (h *HeaderWithExecProof) Validate() error {
   157  	return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, h.PayloadHeader.PayloadRoot())
   158  }
   159  
   160  // OptimisticUpdate proves sync committee commitment on the attested beacon header.
   161  // It also proves the belonging execution payload header with a Merkle proof.
   162  //
   163  // See data structure definition here:
   164  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
   165  type OptimisticUpdate struct {
   166  	Attested HeaderWithExecProof
   167  	// Sync committee BLS signature aggregate
   168  	Signature SyncAggregate
   169  	// Slot in which the signature has been created (newer than Header.Slot,
   170  	// determines the signing sync committee)
   171  	SignatureSlot uint64
   172  }
   173  
   174  // SignedHeader returns the signed attested header of the update.
   175  func (u *OptimisticUpdate) SignedHeader() SignedHeader {
   176  	return SignedHeader{
   177  		Header:        u.Attested.Header,
   178  		Signature:     u.Signature,
   179  		SignatureSlot: u.SignatureSlot,
   180  	}
   181  }
   182  
   183  // Validate verifies the Merkle proof proving the execution payload header.
   184  // Note that the sync committee signature of the attested header should be
   185  // verified separately by a synced committee chain.
   186  func (u *OptimisticUpdate) Validate() error {
   187  	return u.Attested.Validate()
   188  }
   189  
   190  // FinalityUpdate proves a finalized beacon header by a sync committee commitment
   191  // on an attested beacon header, referring to the latest finalized header with a
   192  // Merkle proof.
   193  // It also proves the execution payload header belonging to both the attested and
   194  // the finalized beacon header with Merkle proofs.
   195  //
   196  // See data structure definition here:
   197  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
   198  type FinalityUpdate struct {
   199  	Version             string
   200  	Attested, Finalized HeaderWithExecProof
   201  	FinalityBranch      merkle.Values
   202  	// Sync committee BLS signature aggregate
   203  	Signature SyncAggregate
   204  	// Slot in which the signature has been created (newer than Header.Slot,
   205  	// determines the signing sync committee)
   206  	SignatureSlot uint64
   207  }
   208  
   209  // SignedHeader returns the signed attested header of the update.
   210  func (u *FinalityUpdate) SignedHeader() SignedHeader {
   211  	return SignedHeader{
   212  		Header:        u.Attested.Header,
   213  		Signature:     u.Signature,
   214  		SignatureSlot: u.SignatureSlot,
   215  	}
   216  }
   217  
   218  // Validate verifies the Merkle proofs proving the finalized beacon header and
   219  // the execution payload headers belonging to the attested and finalized headers.
   220  // Note that the sync committee signature of the attested header should be
   221  // verified separately by a synced committee chain.
   222  func (u *FinalityUpdate) Validate() error {
   223  	if err := u.Attested.Validate(); err != nil {
   224  		return err
   225  	}
   226  	if err := u.Finalized.Validate(); err != nil {
   227  		return err
   228  	}
   229  	return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock(u.Version), u.FinalityBranch, merkle.Value(u.Finalized.Hash()))
   230  }
   231  
   232  // ChainHeadEvent returns an authenticated execution payload associated with the
   233  // latest accepted head of the beacon chain, along with the hash of the latest
   234  // finalized execution block.
   235  type ChainHeadEvent struct {
   236  	BeaconHead   Header
   237  	Block        *ctypes.Block
   238  	ExecRequests [][]byte    // execution layer requests (added in Electra)
   239  	Finalized    common.Hash // latest finalized block hash
   240  }