github.com/theQRL/go-zond@v0.1.1/beacon/types/update.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/theQRL/go-zond/beacon/merkle"
    24  	"github.com/theQRL/go-zond/beacon/params"
    25  	"github.com/theQRL/go-zond/common"
    26  )
    27  
    28  // LightClientUpdate is a proof of the next sync committee root based on a header
    29  // signed by the sync committee of the given period. Optionally, the update can
    30  // prove quasi-finality by the signed header referring to a previous, finalized
    31  // header from the same period, and the finalized header referring to the next
    32  // sync committee root.
    33  //
    34  // See data structure definition here:
    35  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
    36  type LightClientUpdate struct {
    37  	AttestedHeader          SignedHeader  // Arbitrary header out of the period signed by the sync committee
    38  	NextSyncCommitteeRoot   common.Hash   // Sync committee of the next period advertised in the current one
    39  	NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee
    40  
    41  	FinalizedHeader *Header       `rlp:"nil"` // Optional header to announce a point of finality
    42  	FinalityBranch  merkle.Values // Proof for the announced finality
    43  
    44  	score *UpdateScore // Weight of the update to compare between competing ones
    45  }
    46  
    47  // Validate verifies the validity of the update.
    48  func (update *LightClientUpdate) Validate() error {
    49  	period := update.AttestedHeader.Header.SyncPeriod()
    50  	if SyncPeriod(update.AttestedHeader.SignatureSlot) != period {
    51  		return errors.New("signature slot and signed header are from different periods")
    52  	}
    53  	if update.FinalizedHeader != nil {
    54  		if update.FinalizedHeader.SyncPeriod() != period {
    55  			return errors.New("finalized header is from different period")
    56  		}
    57  		if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil {
    58  			return fmt.Errorf("invalid finalized header proof: %w", err)
    59  		}
    60  	}
    61  	if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil {
    62  		return fmt.Errorf("invalid next sync committee proof: %w", err)
    63  	}
    64  	return nil
    65  }
    66  
    67  // Score returns the UpdateScore describing the proof strength of the update
    68  // Note: thread safety can be ensured by always calling Score on a newly received
    69  // or decoded update before making it potentially available for other threads
    70  func (update *LightClientUpdate) Score() UpdateScore {
    71  	if update.score == nil {
    72  		update.score = &UpdateScore{
    73  			SignerCount:     uint32(update.AttestedHeader.Signature.SignerCount()),
    74  			SubPeriodIndex:  uint32(update.AttestedHeader.Header.Slot & 0x1fff),
    75  			FinalizedHeader: update.FinalizedHeader != nil,
    76  		}
    77  	}
    78  	return *update.score
    79  }
    80  
    81  // UpdateScore allows the comparison between updates at the same period in order
    82  // to find the best update chain that provides the strongest proof of being canonical.
    83  //
    84  // UpdateScores have a tightly packed binary encoding format for efficient p2p
    85  // protocol transmission. Each UpdateScore is encoded in 3 bytes.
    86  // When interpreted as a 24 bit little indian unsigned integer:
    87  //   - the lowest 10 bits contain the number of signers in the header signature aggregate
    88  //   - the next 13 bits contain the "sub-period index" which is he signed header's
    89  //     slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being
    90  //     re-orged before the previous period boundary in case of non-finalized updates)
    91  //   - the highest bit is set when the update is finalized (meaning that the finality
    92  //     header referenced by the signed header is in the same period as the signed
    93  //     header, making reorgs before the period boundary impossible
    94  type UpdateScore struct {
    95  	SignerCount     uint32 // number of signers in the header signature aggregate
    96  	SubPeriodIndex  uint32 // signed header's slot modulo params.SyncPeriodLength
    97  	FinalizedHeader bool   // update is considered finalized if has finalized header from the same period and 2/3 signatures
    98  }
    99  
   100  // finalized returns true if the update has a header signed by at least 2/3 of
   101  // the committee, referring to a finalized header that refers to the next sync
   102  // committee. This condition is a close approximation of the actual finality
   103  // condition that can only be verified by full beacon nodes.
   104  func (u *UpdateScore) finalized() bool {
   105  	return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority
   106  }
   107  
   108  // BetterThan returns true if update u is considered better than w.
   109  func (u UpdateScore) BetterThan(w UpdateScore) bool {
   110  	var (
   111  		uFinalized = u.finalized()
   112  		wFinalized = w.finalized()
   113  	)
   114  	if uFinalized != wFinalized {
   115  		return uFinalized
   116  	}
   117  	return u.SignerCount > w.SignerCount
   118  }