Add in State Slot for Sync Committee Cache (#10475)

* add changes

* Update beacon-chain/core/helpers/sync_committee_test.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
Co-authored-by: terence tsao <terence@prysmaticlabs.com>
This commit is contained in:
Nishant Das
2022-04-22 16:03:32 +08:00
committed by GitHub
parent 2fd7c926ed
commit 7765d275d1
2 changed files with 70 additions and 14 deletions

View File

@@ -11,6 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/time/slots"
log "github.com/sirupsen/logrus"
@@ -31,7 +32,7 @@ func IsCurrentPeriodSyncCommittee(
if err != nil {
return false, err
}
indices, err := syncCommitteeCache.CurrentPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
indices, err := syncCommitteeCache.CurrentPeriodIndexPosition(root, valIdx)
if err == cache.ErrNonExistingSyncCommitteeKey {
val, err := st.ValidatorAtIndex(valIdx)
if err != nil {
@@ -44,7 +45,7 @@ func IsCurrentPeriodSyncCommittee(
// Fill in the cache on miss.
go func() {
if err := syncCommitteeCache.UpdatePositionsInCommittee(bytesutil.ToBytes32(root), st); err != nil {
if err := syncCommitteeCache.UpdatePositionsInCommittee(root, st); err != nil {
log.Errorf("Could not fill sync committee cache on miss: %v", err)
}
}()
@@ -68,7 +69,7 @@ func IsNextPeriodSyncCommittee(
if err != nil {
return false, err
}
indices, err := syncCommitteeCache.NextPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
indices, err := syncCommitteeCache.NextPeriodIndexPosition(root, valIdx)
if err == cache.ErrNonExistingSyncCommitteeKey {
val, err := st.ValidatorAtIndex(valIdx)
if err != nil {
@@ -95,7 +96,7 @@ func CurrentPeriodSyncSubcommitteeIndices(
if err != nil {
return nil, err
}
indices, err := syncCommitteeCache.CurrentPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
indices, err := syncCommitteeCache.CurrentPeriodIndexPosition(root, valIdx)
if err == cache.ErrNonExistingSyncCommitteeKey {
val, err := st.ValidatorAtIndex(valIdx)
if err != nil {
@@ -108,7 +109,7 @@ func CurrentPeriodSyncSubcommitteeIndices(
// Fill in the cache on miss.
go func() {
if err := syncCommitteeCache.UpdatePositionsInCommittee(bytesutil.ToBytes32(root), st); err != nil {
if err := syncCommitteeCache.UpdatePositionsInCommittee(root, st); err != nil {
log.Errorf("Could not fill sync committee cache on miss: %v", err)
}
}()
@@ -129,7 +130,7 @@ func NextPeriodSyncSubcommitteeIndices(
if err != nil {
return nil, err
}
indices, err := syncCommitteeCache.NextPeriodIndexPosition(bytesutil.ToBytes32(root), valIdx)
indices, err := syncCommitteeCache.NextPeriodIndexPosition(root, valIdx)
if err == cache.ErrNonExistingSyncCommitteeKey {
val, err := st.ValidatorAtIndex(valIdx)
if err != nil {
@@ -169,7 +170,7 @@ func UpdateSyncCommitteeCache(st state.BeaconStateAltair) error {
return err
}
return syncCommitteeCache.UpdatePositionsInCommittee(prevBlockRoot, st)
return syncCommitteeCache.UpdatePositionsInCommittee(combineRootAndSlot(prevBlockRoot[:], uint64(header.Slot)), st)
}
// Loop through `pubKeys` for matching `pubKey` and get the indices where it matches.
@@ -186,19 +187,19 @@ func findSubCommitteeIndices(pubKey []byte, pubKeys [][]byte) []types.CommitteeI
// 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) {
func syncPeriodBoundaryRoot(st state.ReadOnlyBeaconState) ([32]byte, error) {
// Can't call `BlockRoot` until the first slot.
if st.Slot() == params.BeaconConfig().GenesisSlot {
return params.BeaconConfig().ZeroHash[:], nil
return params.BeaconConfig().ZeroHash, nil
}
startEpoch, err := slots.SyncCommitteePeriodStartEpoch(time.CurrentEpoch(st))
if err != nil {
return nil, err
return [32]byte{}, err
}
startEpochSlot, err := slots.EpochStart(startEpoch)
if err != nil {
return nil, err
return [32]byte{}, err
}
// Prevent underflow
@@ -206,5 +207,15 @@ func syncPeriodBoundaryRoot(st state.ReadOnlyBeaconState) ([]byte, error) {
startEpochSlot--
}
return BlockRootAtSlot(st, startEpochSlot)
root, err := BlockRootAtSlot(st, startEpochSlot)
if err != nil {
return [32]byte{}, err
}
return combineRootAndSlot(root, uint64(startEpochSlot)), nil
}
func combineRootAndSlot(root []byte, slot uint64) [32]byte {
slotBytes := bytesutil.Uint64ToBytesLittleEndian(slot)
keyHash := hash.Hash(append(root, slotBytes...))
return keyHash
}

View File

@@ -1,6 +1,7 @@
package helpers
import (
"math/rand"
"strconv"
"testing"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -234,7 +236,7 @@ func TestCurrentEpochSyncSubcommitteeIndices_UsingCommittee(t *testing.T) {
require.NoError(t, err)
// Test that cache was empty.
_, err = syncCommitteeCache.CurrentPeriodIndexPosition(bytesutil.ToBytes32(root), 0)
_, err = syncCommitteeCache.CurrentPeriodIndexPosition(root, 0)
require.Equal(t, cache.ErrNonExistingSyncCommitteeKey, err)
// Test that helper can retrieve the index given empty cache.
@@ -244,7 +246,7 @@ func TestCurrentEpochSyncSubcommitteeIndices_UsingCommittee(t *testing.T) {
// Test that cache was able to fill on miss.
time.Sleep(100 * time.Millisecond)
index, err = syncCommitteeCache.CurrentPeriodIndexPosition(bytesutil.ToBytes32(root), 0)
index, err = syncCommitteeCache.CurrentPeriodIndexPosition(root, 0)
require.NoError(t, err)
require.DeepEqual(t, []types.CommitteeIndex{0}, index)
}
@@ -384,3 +386,46 @@ func TestUpdateSyncCommitteeCache_BadRoot(t *testing.T) {
err = UpdateSyncCommitteeCache(state)
require.ErrorContains(t, "zero hash state root can't be used to update cache", err)
}
func TestIsCurrentEpochSyncCommittee_SameBlockRoot(t *testing.T) {
validators := make([]*ethpb.Validator, params.BeaconConfig().SyncCommitteeSize)
syncCommittee := &ethpb.SyncCommittee{
AggregatePubkey: bytesutil.PadTo([]byte{}, params.BeaconConfig().BLSPubkeyLength),
}
for i := 0; i < len(validators); i++ {
k := make([]byte, 48)
copy(k, strconv.Itoa(i))
validators[i] = &ethpb.Validator{
PublicKey: k,
}
syncCommittee.Pubkeys = append(syncCommittee.Pubkeys, bytesutil.PadTo(k, 48))
}
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
for i := range blockRoots {
blockRoots[i] = make([]byte, 32)
}
state, err := v2.InitializeFromProto(&ethpb.BeaconStateAltair{
Validators: validators,
BlockRoots: blockRoots,
})
require.NoError(t, err)
require.NoError(t, state.SetCurrentSyncCommittee(syncCommittee))
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
ClearCache()
comIdxs, err := CurrentPeriodSyncSubcommitteeIndices(state, 200)
require.NoError(t, err)
wantedSlot := params.BeaconConfig().EpochsPerSyncCommitteePeriod.Mul(uint64(params.BeaconConfig().SlotsPerEpoch))
assert.NoError(t, state.SetSlot(types.Slot(wantedSlot)))
syncCommittee, err = state.CurrentSyncCommittee()
assert.NoError(t, err)
rand.Shuffle(len(syncCommittee.Pubkeys), func(i, j int) {
syncCommittee.Pubkeys[i], syncCommittee.Pubkeys[j] = syncCommittee.Pubkeys[j], syncCommittee.Pubkeys[i]
})
require.NoError(t, state.SetCurrentSyncCommittee(syncCommittee))
newIdxs, err := CurrentPeriodSyncSubcommitteeIndices(state, 200)
require.NoError(t, err)
require.DeepNotEqual(t, comIdxs, newIdxs)
}