func (s *Service) CurrentEpoch() phase0.Epoch {
	return phase0.Epoch(uint64(s.CurrentSlot()) / s.slotsPerEpoch)
}
CurrentEpoch provides the current epoch.
package standard
import (
	"bytes"
	"context"
	"time"
	eth2client "github.com/attestantio/go-eth2-client"
	"github.com/attestantio/go-eth2-client/spec/phase0"
	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	zerologger "github.com/rs/zerolog/log"
)
type Service struct {
	genesisTime                  time.Time
	slotDuration                 time.Duration
	slotsPerEpoch                uint64
	epochsPerSyncCommitteePeriod uint64
	altairForkEpoch              phase0.Epoch
}
var log zerolog.Logger
func New(ctx context.Context, params ...Parameter) (*Service, error) {
	parameters, err := parseAndCheckParameters(params...)
	if err != nil {
		return nil, errors.Wrap(err, "problem with parameters")
	}
	log = zerologger.With().Str("service", "chaintime").Str("impl", "standard").Logger().Level(parameters.logLevel)
	genesisTime, err := parameters.genesisTimeProvider.GenesisTime(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "failed to obtain genesis time")
	}
	log.Trace().Time("genesis_time", genesisTime).Msg("Obtained genesis time")
	spec, err := parameters.specProvider.Spec(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "failed to obtain spec")
	}
	tmp, exists := spec["SECONDS_PER_SLOT"]
	if !exists {
		return nil, errors.New("SECONDS_PER_SLOT not found in spec")
	}
	slotDuration, ok := tmp.(time.Duration)
	if !ok {
		return nil, errors.New("SECONDS_PER_SLOT of unexpected type")
	}
	tmp, exists = spec["SLOTS_PER_EPOCH"]
	if !exists {
		return nil, errors.New("SLOTS_PER_EPOCH not found in spec")
	}
	slotsPerEpoch, ok := tmp.(uint64)
	if !ok {
		return nil, errors.New("SLOTS_PER_EPOCH of unexpected type")
	}
	var epochsPerSyncCommitteePeriod uint64
	if tmp, exists := spec["EPOCHS_PER_SYNC_COMMITTEE_PERIOD"]; exists {
		tmp2, ok := tmp.(uint64)
		if !ok {
			return nil, errors.New("EPOCHS_PER_SYNC_COMMITTEE_PERIOD of unexpected type")
		}
		epochsPerSyncCommitteePeriod = tmp2
	}
	altairForkEpoch, err := fetchAltairForkEpoch(ctx, parameters.forkScheduleProvider)
	if err != nil {
		altairForkEpoch = 0xffffffffffffffff
	}
	log.Trace().Uint64("epoch", uint64(altairForkEpoch)).Msg("Obtained Altair fork epoch")
	s := &Service{
		genesisTime:                  genesisTime,
		slotDuration:                 slotDuration,
		slotsPerEpoch:                slotsPerEpoch,
		epochsPerSyncCommitteePeriod: epochsPerSyncCommitteePeriod,
		altairForkEpoch:              altairForkEpoch,
	}
	return s, nil
}
func (s *Service) GenesisTime() time.Time {
	return s.genesisTime
}
func (s *Service) StartOfSlot(slot phase0.Slot) time.Time {
	return s.genesisTime.Add(time.Duration(slot) * s.slotDuration)
}
func (s *Service) StartOfEpoch(epoch phase0.Epoch) time.Time {
	return s.genesisTime.Add(time.Duration(uint64(epoch)*s.slotsPerEpoch) * s.slotDuration)
}
func (s *Service) CurrentSlot() phase0.Slot {
	if s.genesisTime.After(time.Now()) {
		return 0
	}
	return phase0.Slot(uint64(time.Since(s.genesisTime).Seconds()) / uint64(s.slotDuration.Seconds()))
}