github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/beacon/light/sync/head_sync.go (about) 1 // Copyright 2023 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 sync 18 19 import ( 20 "github.com/ethereum/go-ethereum/beacon/light/request" 21 "github.com/ethereum/go-ethereum/beacon/types" 22 "github.com/ethereum/go-ethereum/log" 23 ) 24 25 type headTracker interface { 26 ValidateOptimistic(update types.OptimisticUpdate) (bool, error) 27 ValidateFinality(head types.FinalityUpdate) (bool, error) 28 ValidatedFinality() (types.FinalityUpdate, bool) 29 SetPrefetchHead(head types.HeadInfo) 30 } 31 32 // HeadSync implements request.Module; it updates the validated and prefetch 33 // heads of HeadTracker based on the EvHead and EvSignedHead events coming from 34 // registered servers. 35 // It can also postpone the validation of the latest announced signed head 36 // until the committee chain is synced up to at least the required period. 37 type HeadSync struct { 38 headTracker headTracker 39 chain committeeChain 40 nextSyncPeriod uint64 41 chainInit bool 42 unvalidatedOptimistic map[request.Server]types.OptimisticUpdate 43 unvalidatedFinality map[request.Server]types.FinalityUpdate 44 serverHeads map[request.Server]types.HeadInfo 45 reqFinalityEpoch map[request.Server]uint64 // next epoch to request finality update 46 headServerCount map[types.HeadInfo]headServerCount 47 headCounter uint64 48 prefetchHead types.HeadInfo 49 } 50 51 // headServerCount is associated with most recently seen head infos; it counts 52 // the number of servers currently having the given head info as their announced 53 // head and a counter signaling how recent that head is. 54 // This data is used for selecting the prefetch head. 55 type headServerCount struct { 56 serverCount int 57 headCounter uint64 58 } 59 60 // NewHeadSync creates a new HeadSync. 61 func NewHeadSync(headTracker headTracker, chain committeeChain) *HeadSync { 62 s := &HeadSync{ 63 headTracker: headTracker, 64 chain: chain, 65 unvalidatedOptimistic: make(map[request.Server]types.OptimisticUpdate), 66 unvalidatedFinality: make(map[request.Server]types.FinalityUpdate), 67 serverHeads: make(map[request.Server]types.HeadInfo), 68 headServerCount: make(map[types.HeadInfo]headServerCount), 69 reqFinalityEpoch: make(map[request.Server]uint64), 70 } 71 return s 72 } 73 74 // Process implements request.Module. 75 func (s *HeadSync) Process(requester request.Requester, events []request.Event) { 76 nextPeriod, chainInit := s.chain.NextSyncPeriod() 77 if nextPeriod != s.nextSyncPeriod || chainInit != s.chainInit { 78 s.nextSyncPeriod, s.chainInit = nextPeriod, chainInit 79 s.processUnvalidatedUpdates() 80 } 81 82 for _, event := range events { 83 switch event.Type { 84 case EvNewHead: 85 s.setServerHead(event.Server, event.Data.(types.HeadInfo)) 86 case EvNewOptimisticUpdate: 87 update := event.Data.(types.OptimisticUpdate) 88 s.newOptimisticUpdate(event.Server, update) 89 epoch := update.Attested.Epoch() 90 if epoch < s.reqFinalityEpoch[event.Server] { 91 continue 92 } 93 if finality, ok := s.headTracker.ValidatedFinality(); ok && finality.Attested.Header.Epoch() >= epoch { 94 continue 95 } 96 requester.Send(event.Server, ReqFinality{}) 97 s.reqFinalityEpoch[event.Server] = epoch + 1 98 case EvNewFinalityUpdate: 99 s.newFinalityUpdate(event.Server, event.Data.(types.FinalityUpdate)) 100 case request.EvResponse: 101 _, _, resp := event.RequestInfo() 102 s.newFinalityUpdate(event.Server, resp.(types.FinalityUpdate)) 103 case request.EvUnregistered: 104 s.setServerHead(event.Server, types.HeadInfo{}) 105 delete(s.serverHeads, event.Server) 106 delete(s.unvalidatedOptimistic, event.Server) 107 delete(s.unvalidatedFinality, event.Server) 108 } 109 } 110 } 111 112 // newOptimisticUpdate handles received optimistic update; either validates it if 113 // the chain is properly synced or stores it for further validation. 114 func (s *HeadSync) newOptimisticUpdate(server request.Server, optimisticUpdate types.OptimisticUpdate) { 115 if !s.chainInit || types.SyncPeriod(optimisticUpdate.SignatureSlot) > s.nextSyncPeriod { 116 s.unvalidatedOptimistic[server] = optimisticUpdate 117 return 118 } 119 if _, err := s.headTracker.ValidateOptimistic(optimisticUpdate); err != nil { 120 log.Debug("Error validating optimistic update", "error", err) 121 } 122 } 123 124 // newFinalityUpdate handles received finality update; either validates it if 125 // the chain is properly synced or stores it for further validation. 126 func (s *HeadSync) newFinalityUpdate(server request.Server, finalityUpdate types.FinalityUpdate) { 127 if !s.chainInit || types.SyncPeriod(finalityUpdate.SignatureSlot) > s.nextSyncPeriod { 128 s.unvalidatedFinality[server] = finalityUpdate 129 return 130 } 131 if _, err := s.headTracker.ValidateFinality(finalityUpdate); err != nil { 132 log.Debug("Error validating finality update", "error", err) 133 } 134 } 135 136 // processUnvalidatedUpdates iterates the list of unvalidated updates and validates 137 // those which can be validated. 138 func (s *HeadSync) processUnvalidatedUpdates() { 139 if !s.chainInit { 140 return 141 } 142 for server, optimisticUpdate := range s.unvalidatedOptimistic { 143 if types.SyncPeriod(optimisticUpdate.SignatureSlot) <= s.nextSyncPeriod { 144 if _, err := s.headTracker.ValidateOptimistic(optimisticUpdate); err != nil { 145 log.Debug("Error validating deferred optimistic update", "error", err) 146 } 147 delete(s.unvalidatedOptimistic, server) 148 } 149 } 150 for server, finalityUpdate := range s.unvalidatedFinality { 151 if types.SyncPeriod(finalityUpdate.SignatureSlot) <= s.nextSyncPeriod { 152 if _, err := s.headTracker.ValidateFinality(finalityUpdate); err != nil { 153 log.Debug("Error validating deferred finality update", "error", err) 154 } 155 delete(s.unvalidatedFinality, server) 156 } 157 } 158 } 159 160 // setServerHead processes non-validated server head announcements and updates 161 // the prefetch head if necessary. 162 func (s *HeadSync) setServerHead(server request.Server, head types.HeadInfo) bool { 163 if oldHead, ok := s.serverHeads[server]; ok { 164 if head == oldHead { 165 return false 166 } 167 h := s.headServerCount[oldHead] 168 if h.serverCount--; h.serverCount > 0 { 169 s.headServerCount[oldHead] = h 170 } else { 171 delete(s.headServerCount, oldHead) 172 } 173 } 174 if head != (types.HeadInfo{}) { 175 h, ok := s.headServerCount[head] 176 if !ok { 177 s.headCounter++ 178 h.headCounter = s.headCounter 179 } 180 h.serverCount++ 181 s.headServerCount[head] = h 182 s.serverHeads[server] = head 183 } else { 184 delete(s.serverHeads, server) 185 } 186 var ( 187 bestHead types.HeadInfo 188 bestHeadInfo headServerCount 189 ) 190 for head, headServerCount := range s.headServerCount { 191 if headServerCount.serverCount > bestHeadInfo.serverCount || 192 (headServerCount.serverCount == bestHeadInfo.serverCount && headServerCount.headCounter > bestHeadInfo.headCounter) { 193 bestHead, bestHeadInfo = head, headServerCount 194 } 195 } 196 if bestHead == s.prefetchHead { 197 return false 198 } 199 s.prefetchHead = bestHead 200 s.headTracker.SetPrefetchHead(bestHead) 201 return true 202 }