github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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 Header Header 40 CommitteeRoot common.Hash 41 Committee *SerializedSyncCommittee `rlp:"-"` 42 CommitteeBranch merkle.Values 43 } 44 45 // Validate verifies the proof included in BootstrapData. 46 func (c *BootstrapData) Validate() error { 47 if c.CommitteeRoot != c.Committee.Root() { 48 return errors.New("wrong committee root") 49 } 50 return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee, c.CommitteeBranch, merkle.Value(c.CommitteeRoot)) 51 } 52 53 // LightClientUpdate is a proof of the next sync committee root based on a header 54 // signed by the sync committee of the given period. Optionally, the update can 55 // prove quasi-finality by the signed header referring to a previous, finalized 56 // header from the same period, and the finalized header referring to the next 57 // sync committee root. 58 // 59 // See data structure definition here: 60 // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate 61 type LightClientUpdate struct { 62 AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee 63 NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one 64 NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee 65 66 FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality 67 FinalityBranch merkle.Values // Proof for the announced finality 68 69 score *UpdateScore // Weight of the update to compare between competing ones 70 } 71 72 // Validate verifies the validity of the update. 73 func (update *LightClientUpdate) Validate() error { 74 period := update.AttestedHeader.Header.SyncPeriod() 75 if SyncPeriod(update.AttestedHeader.SignatureSlot) != period { 76 return errors.New("signature slot and signed header are from different periods") 77 } 78 if update.FinalizedHeader != nil { 79 if update.FinalizedHeader.SyncPeriod() != period { 80 return errors.New("finalized header is from different period") 81 } 82 if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil { 83 return fmt.Errorf("invalid finalized header proof: %w", err) 84 } 85 } 86 if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil { 87 return fmt.Errorf("invalid next sync committee proof: %w", err) 88 } 89 return nil 90 } 91 92 // Score returns the UpdateScore describing the proof strength of the update 93 // Note: thread safety can be ensured by always calling Score on a newly received 94 // or decoded update before making it potentially available for other threads 95 func (update *LightClientUpdate) Score() UpdateScore { 96 if update.score == nil { 97 update.score = &UpdateScore{ 98 SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()), 99 SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff), 100 FinalizedHeader: update.FinalizedHeader != nil, 101 } 102 } 103 return *update.score 104 } 105 106 // UpdateScore allows the comparison between updates at the same period in order 107 // to find the best update chain that provides the strongest proof of being canonical. 108 // 109 // UpdateScores have a tightly packed binary encoding format for efficient p2p 110 // protocol transmission. Each UpdateScore is encoded in 3 bytes. 111 // When interpreted as a 24 bit little indian unsigned integer: 112 // - the lowest 10 bits contain the number of signers in the header signature aggregate 113 // - the next 13 bits contain the "sub-period index" which is he signed header's 114 // slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being 115 // re-orged before the previous period boundary in case of non-finalized updates) 116 // - the highest bit is set when the update is finalized (meaning that the finality 117 // header referenced by the signed header is in the same period as the signed 118 // header, making reorgs before the period boundary impossible 119 type UpdateScore struct { 120 SignerCount uint32 // number of signers in the header signature aggregate 121 SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength 122 FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures 123 } 124 125 // finalized returns true if the update has a header signed by at least 2/3 of 126 // the committee, referring to a finalized header that refers to the next sync 127 // committee. This condition is a close approximation of the actual finality 128 // condition that can only be verified by full beacon nodes. 129 func (u *UpdateScore) finalized() bool { 130 return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority 131 } 132 133 // BetterThan returns true if update u is considered better than w. 134 func (u UpdateScore) BetterThan(w UpdateScore) bool { 135 var ( 136 uFinalized = u.finalized() 137 wFinalized = w.finalized() 138 ) 139 if uFinalized != wFinalized { 140 return uFinalized 141 } 142 return u.SignerCount > w.SignerCount 143 } 144 145 // HeaderWithExecProof contains a beacon header and proves the belonging execution 146 // payload header with a Merkle proof. 147 type HeaderWithExecProof struct { 148 Header 149 PayloadHeader *ExecutionHeader 150 PayloadBranch merkle.Values 151 } 152 153 // Validate verifies the Merkle proof of the execution payload header. 154 func (h *HeaderWithExecProof) Validate() error { 155 return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, h.PayloadHeader.PayloadRoot()) 156 } 157 158 // OptimisticUpdate proves sync committee commitment on the attested beacon header. 159 // It also proves the belonging execution payload header with a Merkle proof. 160 // 161 // See data structure definition here: 162 // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate 163 type OptimisticUpdate struct { 164 Attested HeaderWithExecProof 165 // Sync committee BLS signature aggregate 166 Signature SyncAggregate 167 // Slot in which the signature has been created (newer than Header.Slot, 168 // determines the signing sync committee) 169 SignatureSlot uint64 170 } 171 172 // SignedHeader returns the signed attested header of the update. 173 func (u *OptimisticUpdate) SignedHeader() SignedHeader { 174 return SignedHeader{ 175 Header: u.Attested.Header, 176 Signature: u.Signature, 177 SignatureSlot: u.SignatureSlot, 178 } 179 } 180 181 // Validate verifies the Merkle proof proving the execution payload header. 182 // Note that the sync committee signature of the attested header should be 183 // verified separately by a synced committee chain. 184 func (u *OptimisticUpdate) Validate() error { 185 return u.Attested.Validate() 186 } 187 188 // FinalityUpdate proves a finalized beacon header by a sync committee commitment 189 // on an attested beacon header, referring to the latest finalized header with a 190 // Merkle proof. 191 // It also proves the execution payload header belonging to both the attested and 192 // the finalized beacon header with Merkle proofs. 193 // 194 // See data structure definition here: 195 // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate 196 type FinalityUpdate struct { 197 Attested, Finalized HeaderWithExecProof 198 FinalityBranch merkle.Values 199 // Sync committee BLS signature aggregate 200 Signature SyncAggregate 201 // Slot in which the signature has been created (newer than Header.Slot, 202 // determines the signing sync committee) 203 SignatureSlot uint64 204 } 205 206 // SignedHeader returns the signed attested header of the update. 207 func (u *FinalityUpdate) SignedHeader() SignedHeader { 208 return SignedHeader{ 209 Header: u.Attested.Header, 210 Signature: u.Signature, 211 SignatureSlot: u.SignatureSlot, 212 } 213 } 214 215 // Validate verifies the Merkle proofs proving the finalized beacon header and 216 // the execution payload headers belonging to the attested and finalized headers. 217 // Note that the sync committee signature of the attested header should be 218 // verified separately by a synced committee chain. 219 func (u *FinalityUpdate) Validate() error { 220 if err := u.Attested.Validate(); err != nil { 221 return err 222 } 223 if err := u.Finalized.Validate(); err != nil { 224 return err 225 } 226 return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock, u.FinalityBranch, merkle.Value(u.Finalized.Hash())) 227 } 228 229 // ChainHeadEvent returns an authenticated execution payload associated with the 230 // latest accepted head of the beacon chain, along with the hash of the latest 231 // finalized execution block. 232 type ChainHeadEvent struct { 233 BeaconHead Header 234 Block *ctypes.Block 235 Finalized common.Hash 236 }