func (s *Service) ValidatingAccountsForEpoch(ctx context.Context, epoch phase0.Epoch) (map[phase0.ValidatorIndex]e2wtypes.Account, error) {
	stateCount := map[api.ValidatorState]uint64{
		api.ValidatorStateUnknown:            0,
		api.ValidatorStatePendingInitialized: 0,
		api.ValidatorStatePendingQueued:      0,
		api.ValidatorStateActiveOngoing:      0,
		api.ValidatorStateActiveExiting:      0,
		api.ValidatorStateActiveSlashed:      0,
		api.ValidatorStateExitedUnslashed:    0,
		api.ValidatorStateExitedSlashed:      0,
		api.ValidatorStateWithdrawalPossible: 0,
		api.ValidatorStateWithdrawalDone:     0,
	}
	validatingAccounts := make(map[phase0.ValidatorIndex]e2wtypes.Account)
	pubKeys := make([]phase0.BLSPubKey, 0, len(s.accounts))
	for pubKey := range s.accounts {
		pubKeys = append(pubKeys, pubKey)
	}
	validators := s.validatorsManager.ValidatorsByPubKey(ctx, pubKeys)
	for index, validator := range validators {
		state := api.ValidatorToState(validator, epoch, s.farFutureEpoch)
		stateCount[state]++
		if state == api.ValidatorStateActiveOngoing || state == api.ValidatorStateActiveExiting {
			account := s.accounts[validator.PublicKey]
			log.Trace().
				Str("name", account.Name()).
				Str("public_key", fmt.Sprintf("%x", account.PublicKey().Marshal())).
				Uint64("index", uint64(index)).
				Str("state", state.String()).
				Msg("Validating account")
			validatingAccounts[index] = account
		}
	}
	if epoch == s.currentEpochProvider.CurrentEpoch() {
		stateCount[api.ValidatorStateUnknown] += uint64(len(s.accounts) - len(validators))
		for state, count := range stateCount {
			s.monitor.Accounts(strings.ToLower(state.String()), count)
		}
	}
	return validatingAccounts, nil
}
ValidatingAccountsForEpoch obtains the validating accounts for a given epoch.
package wallet
import (
	"context"
	"fmt"
	"regexp"
	"strings"
	"sync"
	eth2client "github.com/attestantio/go-eth2-client"
	api "github.com/attestantio/go-eth2-client/api/v1"
	"github.com/attestantio/go-eth2-client/spec/phase0"
	"github.com/attestantio/vouch/services/chaintime"
	"github.com/attestantio/vouch/services/metrics"
	"github.com/attestantio/vouch/services/validatorsmanager"
	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	zerologger "github.com/rs/zerolog/log"
	"github.com/wealdtech/go-bytesutil"
	e2wallet "github.com/wealdtech/go-eth2-wallet"
	filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem"
	e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
	"golang.org/x/sync/semaphore"
)
type Service struct {
	mutex                sync.RWMutex
	monitor              metrics.AccountManagerMonitor
	processConcurrency   int64
	stores               []e2wtypes.Store
	accountPaths         []string
	passphrases          [][]byte
	accounts             map[phase0.BLSPubKey]e2wtypes.Account
	validatorsManager    validatorsmanager.Service
	slotsPerEpoch        phase0.Slot
	domainProvider       eth2client.DomainProvider
	farFutureEpoch       phase0.Epoch
	currentEpochProvider chaintime.Service
}
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", "accountmanager").Str("impl", "wallet").Logger()
	if parameters.logLevel != log.GetLevel() {
		log = log.Level(parameters.logLevel)
	}
	log.Warn().Msg("The wallet account manager does not provide built-in slashing protection.  Please use the dirk account manager for production systems.")
	stores := make([]e2wtypes.Store, 0, len(parameters.locations))
	if len(parameters.locations) == 0 {
		stores = append(stores, filesystem.New())
	} else {
		for _, location := range parameters.locations {
			stores = append(stores, filesystem.New(filesystem.WithLocation(location)))
		}
	}
	slotsPerEpoch, err := parameters.slotsPerEpochProvider.SlotsPerEpoch(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "failed to obtain slots per epoch")
	}
	farFutureEpoch, err := parameters.farFutureEpochProvider.FarFutureEpoch(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "failed to obtain far future epoch")
	}
	s := &Service{
		monitor:              parameters.monitor,
		processConcurrency:   parameters.processConcurrency,
		stores:               stores,
		accountPaths:         parameters.accountPaths,
		passphrases:          parameters.passphrases,
		validatorsManager:    parameters.validatorsManager,
		slotsPerEpoch:        phase0.Slot(slotsPerEpoch),
		domainProvider:       parameters.domainProvider,
		farFutureEpoch:       farFutureEpoch,
		currentEpochProvider: parameters.currentEpochProvider,
	}
	if err := s.refreshAccounts(ctx); err != nil {
		return nil, errors.Wrap(err, "failed to fetch accounts")
	}
	if err := s.refreshValidators(ctx); err != nil {
		return nil, errors.Wrap(err, "failed to fetch validator states")
	}
	return s, nil
}
func (s *Service) Refresh(ctx context.Context) {
	if err := s.refreshAccounts(ctx); err != nil {
		log.Error().Err(err).Msg("Failed to refresh accounts")
	}
	if err := s.refreshValidators(ctx); err != nil {
		log.Error().Err(err).Msg("Failed to refresh validators")
	}
}
func (s *Service) refreshAccounts(ctx context.Context) error {
	wallets := make(map[string]e2wtypes.Wallet)
	pathsByWallet := make(map[string][]string)
	for _, path := range s.accountPaths {
		pathBits := strings.Split(path, "/")
		var paths []string
		var exists bool
		if paths, exists = pathsByWallet[pathBits[0]]; !exists {
			paths = make([]string, 0)
		}
		pathsByWallet[pathBits[0]] = append(paths, path)
		found := false
		for _, store := range s.stores {
			wallet, err := e2wallet.OpenWallet(pathBits[0], e2wallet.WithStore(store))
			if err == nil {
				wallets[wallet.Name()] = wallet
				found = true
				break
			}
		}
		if !found {
			log.Warn().Str("wallet", pathBits[0]).Msg("Failed to find wallet in any store")
		}
	}
	verificationRegexes := accountPathsToVerificationRegexes(s.accountPaths)
	accounts := make(map[phase0.BLSPubKey]e2wtypes.Account)
	for _, wallet := range wallets {
		s.fetchAccountsForWallet(ctx, wallet, accounts, verificationRegexes)
	}
	log.Trace().Int("accounts", len(accounts)).Msg("Obtained accounts")
	s.mutex.Lock()
	s.accounts = accounts
	s.mutex.Unlock()
	return nil
}
func (s *Service) refreshValidators(ctx context.Context) error {
	accountPubKeys := make([]phase0.BLSPubKey, 0, len(s.accounts))
	for pubKey := range s.accounts {
		accountPubKeys = append(accountPubKeys, pubKey)
	}
	if err := s.validatorsManager.RefreshValidatorsFromBeaconNode(ctx, accountPubKeys); err != nil {
		return errors.Wrap(err, "failed to refresh validators")
	}
	return nil
}