github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/c_event_callbacks.go (about) 1 package gossip 2 3 import ( 4 "errors" 5 "math/big" 6 "sync/atomic" 7 8 "github.com/unicornultrafoundation/go-helios/gossip/dagprocessor" 9 "github.com/unicornultrafoundation/go-helios/hash" 10 "github.com/unicornultrafoundation/go-helios/native/dag" 11 "github.com/unicornultrafoundation/go-helios/native/idx" 12 "github.com/unicornultrafoundation/go-u2u/common" 13 "github.com/unicornultrafoundation/go-u2u/log" 14 15 "github.com/unicornultrafoundation/go-u2u/eventcheck" 16 "github.com/unicornultrafoundation/go-u2u/eventcheck/epochcheck" 17 "github.com/unicornultrafoundation/go-u2u/gossip/emitter" 18 "github.com/unicornultrafoundation/go-u2u/native" 19 "github.com/unicornultrafoundation/go-u2u/native/iblockproc" 20 "github.com/unicornultrafoundation/go-u2u/utils/concurrent" 21 ) 22 23 var ( 24 errStopped = errors.New("service is stopped") 25 errWrongMedianTime = errors.New("wrong event median time") 26 errWrongEpochHash = errors.New("wrong event epoch hash") 27 errNonExistingEpoch = errors.New("epoch doesn't exist") 28 errSameEpoch = errors.New("epoch hasn't changed") 29 errDirtyEvmSnap = errors.New("EVM snapshot is dirty") 30 ) 31 32 func (s *Service) buildEvent(e *native.MutableEventPayload, onIndexed func()) error { 33 // set some unique ID 34 e.SetID(s.uniqueEventIDs.sample()) 35 36 // set PrevEpochHash 37 if e.Lamport() <= 1 { 38 prevEpochHash := s.store.GetEpochState().Hash() 39 e.SetPrevEpochHash(&prevEpochHash) 40 } 41 42 // indexing event without saving 43 defer s.dagIndexer.DropNotFlushed() 44 err := s.dagIndexer.Add(e) 45 if err != nil { 46 return err 47 } 48 49 if onIndexed != nil { 50 onIndexed() 51 } 52 53 e.SetMedianTime(s.dagIndexer.MedianTime(e.ID(), s.store.GetEpochState().EpochStart)) 54 55 // calc initial GasPower 56 e.SetGasPowerUsed(epochcheck.CalcGasPowerUsed(e, s.store.GetRules())) 57 var selfParent *native.Event 58 if e.SelfParent() != nil { 59 selfParent = s.store.GetEvent(*e.SelfParent()) 60 } 61 availableGasPower, err := s.checkers.Gaspowercheck.CalcGasPower(e, selfParent) 62 if err != nil { 63 return err 64 } 65 if e.GasPowerUsed() > availableGasPower.Min() { 66 return emitter.ErrNotEnoughGasPower 67 } 68 e.SetGasPowerLeft(availableGasPower.Sub(e.GasPowerUsed())) 69 return s.engine.Build(e) 70 } 71 72 // processSavedEvent performs processing which depends on event being saved in DB 73 func (s *Service) processSavedEvent(e *native.EventPayload, es *iblockproc.EpochState) error { 74 err := s.dagIndexer.Add(e) 75 if err != nil { 76 return err 77 } 78 79 // check median time 80 if e.MedianTime() != s.dagIndexer.MedianTime(e.ID(), es.EpochStart) { 81 return errWrongMedianTime 82 } 83 84 // aBFT processing 85 return s.engine.Process(e) 86 } 87 88 // saveAndProcessEvent deletes event in a case if it fails validation during event processing 89 func (s *Service) saveAndProcessEvent(e *native.EventPayload, es *iblockproc.EpochState) error { 90 fixEventTxHashes(e) 91 // indexing event 92 s.store.SetEvent(e) 93 defer s.dagIndexer.DropNotFlushed() 94 95 err := s.processSavedEvent(e, es) 96 if err != nil { 97 s.store.DelEvent(e.ID()) 98 return err 99 } 100 101 // save event index after success 102 s.dagIndexer.Flush() 103 return nil 104 } 105 106 func processEventHeads(heads *concurrent.EventsSet, e *native.EventPayload) *concurrent.EventsSet { 107 // track events with no descendants, i.e. "heads" 108 heads.Lock() 109 defer heads.Unlock() 110 heads.Val.Erase(e.Parents()...) 111 heads.Val.Add(e.ID()) 112 return heads 113 } 114 115 func processLastEvent(lasts *concurrent.ValidatorEventsSet, e *native.EventPayload) *concurrent.ValidatorEventsSet { 116 // set validator's last event. we don't care about forks, because this index is used only for emitter 117 lasts.Lock() 118 defer lasts.Unlock() 119 lasts.Val[e.Creator()] = e.ID() 120 return lasts 121 } 122 123 func (s *Service) switchEpochTo(newEpoch idx.Epoch) { 124 s.store.cache.EventIDs.Reset(newEpoch) 125 s.store.SetHighestLamport(0) 126 // reset dag indexer 127 s.store.resetEpochStore(newEpoch) 128 es := s.store.getEpochStore(newEpoch) 129 s.dagIndexer.Reset(s.store.GetValidators(), es.table.DagIndex, func(id hash.Event) dag.Event { 130 return s.store.GetEvent(id) 131 }) 132 // notify event checkers about new validation data 133 s.gasPowerCheckReader.Ctx.Store(NewGasPowerContext(s.store, s.store.GetValidators(), newEpoch, s.store.GetRules().Economy)) // read gaspower check data from disk 134 s.heavyCheckReader.Pubkeys.Store(readEpochPubKeys(s.store, newEpoch)) 135 // notify about new epoch 136 for _, em := range s.emitters { 137 em.OnNewEpoch(s.store.GetValidators(), newEpoch) 138 } 139 s.feed.newEpoch.Send(newEpoch) 140 } 141 142 func (s *Service) SwitchEpochTo(newEpoch idx.Epoch) error { 143 bs, es := s.store.GetHistoryBlockEpochState(newEpoch) 144 if bs == nil { 145 return errNonExistingEpoch 146 } 147 s.engineMu.Lock() 148 defer s.engineMu.Unlock() 149 s.blockProcWg.Wait() 150 if newEpoch == s.store.GetEpoch() { 151 return errSameEpoch 152 } 153 s.store.evm.RebuildEvmSnapshot(common.Hash(bs.FinalizedStateRoot)) 154 err := s.engine.Reset(newEpoch, es.Validators) 155 if err != nil { 156 return err 157 } 158 s.store.SetBlockEpochState(*bs, *es) 159 s.switchEpochTo(newEpoch) 160 s.commit(true) 161 return nil 162 } 163 164 func (s *Service) PauseEvmSnapshot() { 165 s.engineMu.Lock() 166 defer s.engineMu.Unlock() 167 s.blockProcWg.Wait() 168 if !s.store.evm.IsEvmSnapshotPaused() { 169 s.store.evm.PauseEvmSnapshot() 170 } 171 } 172 173 func (s *Service) EvmSnapshotGeneration() bool { 174 gen, _ := s.store.evm.Snaps.Generating() 175 return gen 176 } 177 178 func (s *Service) processEventEpochIndex(e *native.EventPayload, oldEpoch, newEpoch idx.Epoch) { 179 // index DAG heads and last events 180 s.store.SetHeads(oldEpoch, processEventHeads(s.store.GetHeads(oldEpoch), e)) 181 s.store.SetLastEvents(oldEpoch, processLastEvent(s.store.GetLastEvents(oldEpoch), e)) 182 // update highest Lamport 183 if newEpoch != oldEpoch { 184 s.store.SetHighestLamport(0) 185 } else if e.Lamport() > s.store.GetHighestLamport() { 186 s.store.SetHighestLamport(e.Lamport()) 187 } 188 } 189 190 func (s *Service) ReprocessEpochEvents() { 191 s.bootstrapping = true 192 // reprocess epoch events, as epoch DBs don't survive restart 193 s.store.ForEachEpochEvent(s.store.GetEpoch(), func(event *native.EventPayload) bool { 194 err := s.dagIndexer.Add(event) 195 if err != nil { 196 log.Crit("Failed to reindex epoch event", "event", event.String(), "err", err) 197 } 198 s.dagIndexer.Flush() 199 err = s.engine.Process(event) 200 if err != nil { 201 log.Crit("Failed to reprocess epoch event", "event", event.String(), "err", err) 202 } 203 s.processEventEpochIndex(event, event.Epoch(), event.Epoch()) 204 return true 205 }) 206 s.bootstrapping = false 207 } 208 209 // processEvent extends the engine.Process with gossip-specific actions on each event processing 210 func (s *Service) processEvent(e *native.EventPayload) error { 211 // s.engineMu is locked here 212 if s.stopped { 213 return errStopped 214 } 215 if err := s.verWatcher.Pause(); err != nil { 216 return err 217 } 218 if gen, err := s.store.evm.Snaps.Generating(); gen || err != nil { 219 // never allow fullsync while EVM snap is still generating, as it may lead to a race condition 220 s.Log.Warn("EVM snapshot is not ready during event processing", "gen", gen, "err", err) 221 return errDirtyEvmSnap 222 } 223 atomic.StoreUint32(&s.eventBusyFlag, 1) 224 defer atomic.StoreUint32(&s.eventBusyFlag, 0) 225 226 // repeat the checks under the mutex which may depend on volatile data 227 if s.store.HasEvent(e.ID()) { 228 return eventcheck.ErrAlreadyConnectedEvent 229 } 230 if err := s.checkers.Epochcheck.Validate(e); err != nil { 231 return err 232 } 233 234 oldEpoch := s.store.GetEpoch() 235 es := s.store.GetEpochState() 236 237 // check prev epoch hash 238 if e.PrevEpochHash() != nil { 239 if *e.PrevEpochHash() != es.Hash() { 240 s.store.DelEvent(e.ID()) 241 return errWrongEpochHash 242 } 243 } 244 245 // Process LLR votes 246 err := s.processBlockVotes(native.AsSignedBlockVotes(e)) 247 if err != nil && err != eventcheck.ErrAlreadyProcessedBVs { 248 return err 249 } 250 err = s.processEpochVote(native.AsSignedEpochVote(e)) 251 if err != nil && err != eventcheck.ErrAlreadyProcessedEV { 252 return err 253 } 254 255 err = s.saveAndProcessEvent(e, &es) 256 if err != nil { 257 return err 258 } 259 260 newEpoch := s.store.GetEpoch() 261 262 s.processEventEpochIndex(e, oldEpoch, newEpoch) 263 264 for _, em := range s.emitters { 265 em.OnEventConnected(e) 266 } 267 268 if newEpoch != oldEpoch { 269 s.switchEpochTo(newEpoch) 270 } 271 272 s.mayCommit(newEpoch != oldEpoch) 273 274 if s.haltCheck != nil && s.haltCheck(oldEpoch, newEpoch, e.MedianTime().Time()) { 275 // halt syncing 276 s.stopped = true 277 } 278 return nil 279 } 280 281 type uniqueID struct { 282 counter *big.Int 283 } 284 285 func (u *uniqueID) sample() [24]byte { 286 u.counter.Add(u.counter, common.Big1) 287 var id [24]byte 288 copy(id[:], u.counter.Bytes()) 289 return id 290 } 291 292 func (s *Service) DagProcessor() *dagprocessor.Processor { 293 return s.handler.dagProcessor 294 } 295 296 func (s *Service) mayCommit(epochSealing bool) { 297 // s.engineMu is locked here 298 if epochSealing || s.store.IsCommitNeeded() { 299 s.commit(epochSealing) 300 } 301 } 302 303 func (s *Service) commit(epochSealing bool) { 304 // s.engineMu is locked here 305 s.blockProcWg.Wait() 306 // if gcmode is full and snapsync is finalized, clean all the old state trie 307 // and commit the state trie at the current block 308 if !s.store.cfg.EVM.Cache.TrieDirtyDisabled && s.handler.syncStatus.AcceptEvents() { 309 s.store.cleanCommitEVM() 310 } 311 _ = s.store.Commit() 312 if epochSealing { 313 s.store.CaptureEvmKvdbSnapshot() 314 } 315 }