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 }