github.com/prysmaticlabs/prysm@v1.4.4/endtoend/helpers/epochTimer.go (about)

     1  package helpers
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/prysmaticlabs/prysm/shared/timeutils"
     7  )
     8  
     9  // EpochTicker is a special ticker for timing epoch changes.
    10  // The channel emits over the epoch interval, and ensures that
    11  // the ticks are in line with the genesis time. This means that
    12  // the duration between the ticks and the genesis time are always a
    13  // multiple of the epoch duration.
    14  // In addition, the channel returns the new epoch number.
    15  type EpochTicker struct {
    16  	c    chan uint64
    17  	done chan struct{}
    18  }
    19  
    20  // C returns the ticker channel. Call Cancel afterwards to ensure
    21  // that the goroutine exits cleanly.
    22  func (s *EpochTicker) C() <-chan uint64 {
    23  	return s.c
    24  }
    25  
    26  // Done should be called to clean up the ticker.
    27  func (s *EpochTicker) Done() {
    28  	go func() {
    29  		s.done <- struct{}{}
    30  	}()
    31  }
    32  
    33  // NewEpochTicker starts the EpochTicker.
    34  func NewEpochTicker(genesisTime time.Time, secondsPerEpoch uint64) *EpochTicker {
    35  	ticker := &EpochTicker{
    36  		c:    make(chan uint64),
    37  		done: make(chan struct{}),
    38  	}
    39  	ticker.start(genesisTime, secondsPerEpoch, timeutils.Since, timeutils.Until, time.After)
    40  	return ticker
    41  }
    42  
    43  func (s *EpochTicker) start(
    44  	genesisTime time.Time,
    45  	secondsPerEpoch uint64,
    46  	since, until func(time.Time) time.Duration,
    47  	after func(time.Duration) <-chan time.Time) {
    48  
    49  	d := time.Duration(secondsPerEpoch) * time.Second
    50  
    51  	go func() {
    52  		sinceGenesis := since(genesisTime)
    53  
    54  		var nextTickTime time.Time
    55  		var epoch uint64
    56  		if sinceGenesis < 0 {
    57  			// Handle when the current time is before the genesis time.
    58  			nextTickTime = genesisTime
    59  			epoch = 0
    60  		} else {
    61  			nextTick := sinceGenesis.Truncate(d) + d
    62  			nextTickTime = genesisTime.Add(nextTick)
    63  			epoch = uint64(nextTick / d)
    64  		}
    65  
    66  		for {
    67  			waitTime := until(nextTickTime)
    68  			select {
    69  			case <-after(waitTime):
    70  				s.c <- epoch
    71  				epoch++
    72  				nextTickTime = nextTickTime.Add(d)
    73  			case <-s.done:
    74  				return
    75  			}
    76  		}
    77  	}()
    78  }