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  }