Files
prysm/beacon-chain/startup/clock.go
Bastin 92bd211e4d upgrade v6 to v7 (#15989)
* upgrade v6 to v7

* changelog

* update-go-ssz
2025-11-06 16:16:23 +00:00

105 lines
3.2 KiB
Go

package startup
import (
"time"
types "github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/time/slots"
)
// Nower is a function that can return the current time.
// In Clock, Now() will use time.Now by default, but a Nower can be set using WithNower in NewClock
// to customize the return value for Now() in tests.
type Nower func() time.Time
// Clock abstracts important time-related concerns in the beacon chain:
// - provides a time.Now() construct that can be overridden in tests
// - GenesisTime() to know the genesis time or use genesis time determination as a synchronization point.
// - CurrentSlot: convenience conversion for current time -> slot
// (support backwards compatibility with the TimeFetcher interface)
// - GenesisValidatorsRoot: is determined at the same point as genesis time and is needed by some of the same code,
// so it is also bundled for convenience.
type Clock struct {
t time.Time
vr [32]byte
now Nower
}
// GenesisTime returns the genesis timestamp.
func (g *Clock) GenesisTime() time.Time {
return g.t
}
// GenesisValidatorsRoot returns the genesis state validator root
func (g *Clock) GenesisValidatorsRoot() [32]byte {
return g.vr
}
// CurrentSlot returns the current slot relative to the time.Time value that Clock embeds.
func (g *Clock) CurrentSlot() types.Slot {
now := g.now()
return slots.Duration(g.t, now)
}
// CurrentEpoch returns the current epoch relative to the time.Time value that Clock embeds.
func (g *Clock) CurrentEpoch() types.Epoch {
return slots.ToEpoch(g.CurrentSlot())
}
// SlotStart computes the time the given slot begins.
func (g *Clock) SlotStart(slot types.Slot) (time.Time, error) {
return slots.StartTime(g.t, slot)
}
// Now provides a value for time.Now() that can be overridden in tests.
func (g *Clock) Now() time.Time {
return g.now()
}
// ClockOpt is a functional option to change the behavior of a clock value made by NewClock.
// It is primarily intended as a way to inject an alternate time.Now() callback (WithNower) for testing.
type ClockOpt func(*Clock)
// WithNower allows tests in particular to inject an alternate implementation of time.Now (vs using system time)
func WithNower(n Nower) ClockOpt {
return func(g *Clock) {
g.now = n
}
}
// WithTimeAsNow will create a Nower based on the given time.Time and set it as the Now() implementation.
func WithTimeAsNow(t time.Time) ClockOpt {
return func(g *Clock) {
g.now = func() time.Time { return t }
}
}
func WithSlotAsNow(s types.Slot) ClockOpt {
return func(g *Clock) {
g.now = func() time.Time {
t, err := slots.StartTime(g.t, s)
if err != nil {
panic(err) // lint:nopanic -- This is a programming error if genesis/slot are invalid.
}
return t
}
}
}
// NewClock constructs a Clock value from a genesis timestamp (t) and a Genesis Validator Root (vr).
// The WithNower ClockOpt can be used in tests to specify an alternate `time.Now` implementation,
// for instance to return a value for `Now` spanning a certain number of slots from genesis time, to control the current slot.
func NewClock(t time.Time, vr [32]byte, opts ...ClockOpt) *Clock {
c := &Clock{
t: t,
vr: vr,
}
for _, o := range opts {
o(c)
}
if c.now == nil {
c.now = time.Now
}
return c
}