mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-25 12:57:18 +00:00
4beb352e6f
* Move Slot and Epoch functions from helpers to core * limited viz * goimports * fix fuzz build * fix fuzz build * fix * fix Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
210 lines
6.5 KiB
Go
210 lines
6.5 KiB
Go
// Package helpers contains helper functions outlined in the Ethereum Beacon Chain spec, such as
|
|
// computing committees, randao, rewards/penalties, and more.
|
|
package helpers
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/pkg/errors"
|
|
types "github.com/prysmaticlabs/eth2-types"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
syncCommitteeCache = cache.NewSyncCommittee()
|
|
)
|
|
|
|
// IsCurrentPeriodSyncCommittee returns true if the input validator index belongs in the current period sync committee
|
|
// along with the sync committee root.
|
|
// 1. Checks if the public key exists in the sync committee cache
|
|
// 2. If 1 fails, checks if the public key exists in the input current sync committee object
|
|
func IsCurrentPeriodSyncCommittee(
|
|
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
|
|
) (bool, error) {
|
|
root, err := syncPeriodBoundaryRoot(st)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
indices, err := syncCommitteeCache.CurrentPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
|
|
if err == cache.ErrNonExistingSyncCommitteeKey {
|
|
val, err := st.ValidatorAtIndex(valIdx)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
committee, err := st.CurrentSyncCommittee()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// Fill in the cache on miss.
|
|
go func() {
|
|
if err := syncCommitteeCache.UpdatePositionsInCommittee(bytesutil.ToBytes32(root), st); err != nil {
|
|
log.Errorf("Could not fill sync committee cache on miss: %v", err)
|
|
}
|
|
}()
|
|
|
|
return len(findSubCommitteeIndices(val.PublicKey, committee.Pubkeys)) > 0, nil
|
|
}
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return len(indices) > 0, nil
|
|
}
|
|
|
|
// IsNextPeriodSyncCommittee returns true if the input validator index belongs in the next period sync committee
|
|
// along with the sync period boundary root.
|
|
// 1. Checks if the public key exists in the sync committee cache
|
|
// 2. If 1 fails, checks if the public key exists in the input next sync committee object
|
|
func IsNextPeriodSyncCommittee(
|
|
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
|
|
) (bool, error) {
|
|
root, err := syncPeriodBoundaryRoot(st)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
indices, err := syncCommitteeCache.NextPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
|
|
if err == cache.ErrNonExistingSyncCommitteeKey {
|
|
val, err := st.ValidatorAtIndex(valIdx)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
committee, err := st.NextSyncCommittee()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return len(findSubCommitteeIndices(val.PublicKey, committee.Pubkeys)) > 0, nil
|
|
}
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return len(indices) > 0, nil
|
|
}
|
|
|
|
// CurrentPeriodSyncSubcommitteeIndices returns the subcommittee indices of the
|
|
// current period sync committee for input validator.
|
|
func CurrentPeriodSyncSubcommitteeIndices(
|
|
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
|
|
) ([]types.CommitteeIndex, error) {
|
|
root, err := syncPeriodBoundaryRoot(st)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
indices, err := syncCommitteeCache.CurrentPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
|
|
if err == cache.ErrNonExistingSyncCommitteeKey {
|
|
val, err := st.ValidatorAtIndex(valIdx)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
committee, err := st.CurrentSyncCommittee()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Fill in the cache on miss.
|
|
go func() {
|
|
if err := syncCommitteeCache.UpdatePositionsInCommittee(bytesutil.ToBytes32(root), st); err != nil {
|
|
log.Errorf("Could not fill sync committee cache on miss: %v", err)
|
|
}
|
|
}()
|
|
|
|
return findSubCommitteeIndices(val.PublicKey, committee.Pubkeys), nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return indices, nil
|
|
}
|
|
|
|
// NextPeriodSyncSubcommitteeIndices returns the subcommittee indices of the next period sync committee for input validator.
|
|
func NextPeriodSyncSubcommitteeIndices(
|
|
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
|
|
) ([]types.CommitteeIndex, error) {
|
|
root, err := syncPeriodBoundaryRoot(st)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
indices, err := syncCommitteeCache.NextPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
|
|
if err == cache.ErrNonExistingSyncCommitteeKey {
|
|
val, err := st.ValidatorAtIndex(valIdx)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
committee, err := st.NextSyncCommittee()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return findSubCommitteeIndices(val.PublicKey, committee.Pubkeys), nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return indices, nil
|
|
}
|
|
|
|
// UpdateSyncCommitteeCache updates sync committee cache.
|
|
// It uses `state`'s latest block header root as key. To avoid misuse, it disallows
|
|
// block header with state root zeroed out.
|
|
func UpdateSyncCommitteeCache(st state.BeaconStateAltair) error {
|
|
nextSlot := st.Slot() + 1
|
|
if nextSlot%params.BeaconConfig().SlotsPerEpoch != 0 {
|
|
return errors.New("not at the end of the epoch to update cache")
|
|
}
|
|
if core.SlotToEpoch(nextSlot)%params.BeaconConfig().EpochsPerSyncCommitteePeriod != 0 {
|
|
return errors.New("not at sync committee period boundary to update cache")
|
|
}
|
|
|
|
header := st.LatestBlockHeader()
|
|
if bytes.Equal(header.StateRoot, params.BeaconConfig().ZeroHash[:]) {
|
|
return errors.New("zero hash state root can't be used to update cache")
|
|
}
|
|
|
|
prevBlockRoot, err := header.HashTreeRoot()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return syncCommitteeCache.UpdatePositionsInCommittee(prevBlockRoot, st)
|
|
}
|
|
|
|
// Loop through `pubKeys` for matching `pubKey` and get the indices where it matches.
|
|
func findSubCommitteeIndices(pubKey []byte, pubKeys [][]byte) []types.CommitteeIndex {
|
|
var indices []types.CommitteeIndex
|
|
for i, k := range pubKeys {
|
|
if bytes.Equal(k, pubKey) {
|
|
indices = append(indices, types.CommitteeIndex(i))
|
|
}
|
|
}
|
|
return indices
|
|
}
|
|
|
|
// Retrieve the current sync period boundary root by calculating sync period start epoch
|
|
// and calling `BlockRoot`.
|
|
// It uses the boundary slot - 1 for block root. (Ex: SlotsPerEpoch * EpochsPerSyncCommitteePeriod - 1)
|
|
func syncPeriodBoundaryRoot(st state.ReadOnlyBeaconState) ([]byte, error) {
|
|
// Can't call `BlockRoot` until the first slot.
|
|
if st.Slot() == params.BeaconConfig().GenesisSlot {
|
|
return params.BeaconConfig().ZeroHash[:], nil
|
|
}
|
|
|
|
startEpoch, err := core.SyncCommitteePeriodStartEpoch(core.CurrentEpoch(st))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
startEpochSlot, err := core.StartSlot(startEpoch)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Prevent underflow
|
|
if startEpochSlot >= 1 {
|
|
startEpochSlot--
|
|
}
|
|
|
|
return BlockRootAtSlot(st, startEpochSlot)
|
|
}
|