Optimize committee helpers (#4328)

This commit is contained in:
terence tsao
2019-12-19 15:40:51 -08:00
committed by GitHub
parent da637668a8
commit 2e4908e7c4
23 changed files with 161 additions and 118 deletions

View File

@@ -6,6 +6,7 @@ import (
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/params"
) )
@@ -30,6 +31,8 @@ type HeadFetcher interface {
HeadRoot() []byte HeadRoot() []byte
HeadBlock() *ethpb.BeaconBlock HeadBlock() *ethpb.BeaconBlock
HeadState(ctx context.Context) (*pb.BeaconState, error) HeadState(ctx context.Context) (*pb.BeaconState, error)
HeadValidatorsIndices(epoch uint64) ([]uint64, error)
HeadSeed(epoch uint64) ([32]byte, error)
} }
// CanonicalRootFetcher defines a common interface for methods in blockchain service which // CanonicalRootFetcher defines a common interface for methods in blockchain service which
@@ -102,6 +105,16 @@ func (s *Service) HeadState(ctx context.Context) (*pb.BeaconState, error) {
return proto.Clone(s.headState).(*pb.BeaconState), nil return proto.Clone(s.headState).(*pb.BeaconState), nil
} }
// HeadValidatorsIndices returns a list of active validator indices from the head view of a given epoch.
func (s *Service) HeadValidatorsIndices(epoch uint64) ([]uint64, error) {
return helpers.ActiveValidatorIndices(s.headState, epoch)
}
// HeadSeed returns the seed from the head view of a given epoch.
func (s *Service) HeadSeed(epoch uint64) ([32]byte, error) {
return helpers.Seed(s.headState, epoch, params.BeaconConfig().DomainBeaconAttester)
}
// CanonicalRoot returns the canonical root of a given slot. // CanonicalRoot returns the canonical root of a given slot.
func (s *Service) CanonicalRoot(slot uint64) []byte { func (s *Service) CanonicalRoot(slot uint64) []byte {
s.headLock.RLock() s.headLock.RLock()

View File

@@ -171,7 +171,7 @@ func (s *Store) saveCheckpointState(ctx context.Context, baseState *pb.BeaconSta
// verifyAttestation validates input attestation is valid. // verifyAttestation validates input attestation is valid.
func (s *Store) verifyAttestation(ctx context.Context, baseState *pb.BeaconState, a *ethpb.Attestation) (*ethpb.IndexedAttestation, error) { func (s *Store) verifyAttestation(ctx context.Context, baseState *pb.BeaconState, a *ethpb.Attestation) (*ethpb.IndexedAttestation, error) {
committee, err := helpers.BeaconCommittee(baseState, a.Data.Slot, a.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(baseState, a.Data.Slot, a.Data.CommitteeIndex)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -309,7 +309,7 @@ func (s *Store) updateBlockAttestationVote(ctx context.Context, att *ethpb.Attes
if baseState == nil { if baseState == nil {
return errors.New("no state found in db with attestation tgt root") return errors.New("no state found in db with attestation tgt root")
} }
committee, err := helpers.BeaconCommittee(baseState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(baseState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -141,7 +141,7 @@ func TestStore_UpdateBlockAttestationVote(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
committee, err := helpers.BeaconCommittee(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@@ -8,9 +8,11 @@ go_library(
visibility = ["//beacon-chain:__subpackages__"], visibility = ["//beacon-chain:__subpackages__"],
deps = [ deps = [
"//beacon-chain/core/feed/state:go_default_library", "//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db:go_default_library", "//beacon-chain/db:go_default_library",
"//proto/beacon/p2p/v1:go_default_library", "//proto/beacon/p2p/v1:go_default_library",
"//shared/event:go_default_library", "//shared/event:go_default_library",
"//shared/params:go_default_library",
"@com_github_pkg_errors//:go_default_library", "@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library", "@com_github_prysmaticlabs_go_ssz//:go_default_library",

View File

@@ -9,9 +9,11 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-ssz" "github.com/prysmaticlabs/go-ssz"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db" "github.com/prysmaticlabs/prysm/beacon-chain/db"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/event" "github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -131,6 +133,16 @@ func (ms *ChainService) ReceiveAttestationNoPubsub(context.Context, *ethpb.Attes
return nil return nil
} }
// HeadValidatorsIndices mocks the same method in the chain service.
func (ms *ChainService) HeadValidatorsIndices(epoch uint64) ([]uint64, error) {
return helpers.ActiveValidatorIndices(ms.State, epoch)
}
// HeadSeed mocks the same method in the chain service.
func (ms *ChainService) HeadSeed(epoch uint64) ([32]byte, error) {
return helpers.Seed(ms.State, epoch, params.BeaconConfig().DomainBeaconAttester)
}
// GenesisTime mocks the same method in the chain service. // GenesisTime mocks the same method in the chain service.
func (ms *ChainService) GenesisTime() time.Time { func (ms *ChainService) GenesisTime() time.Time {
return ms.Genesis return ms.Genesis

View File

@@ -828,7 +828,7 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *pb.BeaconState,
// VerifyAttestation converts and attestation into an indexed attestation and verifies // VerifyAttestation converts and attestation into an indexed attestation and verifies
// the signature in that attestation. // the signature in that attestation.
func VerifyAttestation(ctx context.Context, beaconState *pb.BeaconState, att *ethpb.Attestation) error { func VerifyAttestation(ctx context.Context, beaconState *pb.BeaconState, att *ethpb.Attestation) error {
committee, err := helpers.BeaconCommittee(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -923,7 +923,7 @@ func TestProcessAttestations_OK(t *testing.T) {
beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world") beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{} beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{}
committee, err := helpers.BeaconCommittee(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -982,7 +982,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world") beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{} beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{}
committee, err := helpers.BeaconCommittee(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -1016,7 +1016,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
CustodyBits: custodyBits2, CustodyBits: custodyBits2,
} }
committee, err = helpers.BeaconCommittee(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex) committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -1065,7 +1065,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world") beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{} beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{}
committee, err := helpers.BeaconCommittee(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -1098,7 +1098,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
CustodyBits: custodyBits2, CustodyBits: custodyBits2,
} }
committee, err = helpers.BeaconCommittee(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex) committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -1223,7 +1223,7 @@ func TestConvertToIndexed_OK(t *testing.T) {
Signature: attestation.Signature, Signature: attestation.Signature,
} }
committee, err := helpers.BeaconCommittee(state, attestation.Data.Slot, attestation.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(state, attestation.Data.Slot, attestation.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@@ -339,8 +339,9 @@ func ProcessFinalUpdates(state *pb.BeaconState) (*pb.BeaconState, error) {
func unslashedAttestingIndices(state *pb.BeaconState, atts []*pb.PendingAttestation) ([]uint64, error) { func unslashedAttestingIndices(state *pb.BeaconState, atts []*pb.PendingAttestation) ([]uint64, error) {
var setIndices []uint64 var setIndices []uint64
seen := make(map[uint64]bool) seen := make(map[uint64]bool)
for _, att := range atts { for _, att := range atts {
committee, err := helpers.BeaconCommittee(state, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -23,6 +23,7 @@ func ProcessAttestations(
v := &Validator{} v := &Validator{}
var err error var err error
for _, a := range append(state.PreviousEpochAttestations, state.CurrentEpochAttestations...) { for _, a := range append(state.PreviousEpochAttestations, state.CurrentEpochAttestations...) {
v.IsCurrentEpochAttester, v.IsCurrentEpochTargetAttester, err = AttestedCurrentEpoch(state, a) v.IsCurrentEpochAttester, v.IsCurrentEpochTargetAttester, err = AttestedCurrentEpoch(state, a)
if err != nil { if err != nil {
@@ -35,8 +36,7 @@ func ProcessAttestations(
return nil, nil, errors.Wrap(err, "could not check validator attested previous epoch") return nil, nil, errors.Wrap(err, "could not check validator attested previous epoch")
} }
// Get attested indices and update the pre computed fields for each attested validators. committee, err := helpers.BeaconCommitteeFromState(state, a.Data.Slot, a.Data.CommitteeIndex)
committee, err := helpers.BeaconCommittee(state, a.Data.Slot, a.Data.CommitteeIndex)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -199,7 +199,8 @@ func TestProcessAttestations(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
committee, err := helpers.BeaconCommittee(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -209,7 +210,7 @@ func TestProcessAttestations(t *testing.T) {
t.Error("Not a prev epoch attester") t.Error("Not a prev epoch attester")
} }
} }
committee, err = helpers.BeaconCommittee(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex) committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@@ -121,21 +121,19 @@ func SlotSignature(state *pb.BeaconState, slot uint64, privKey *bls.SecretKey) (
return privKey.Sign(s[:], d), nil return privKey.Sign(s[:], d), nil
} }
// IsAggregator returns true if the signature is from the input validator. // IsAggregator returns true if the signature is from the input validator. The committee
// count is provided as an argument rather than direct implementation from spec. Having
// committee count as an argument allows cheaper computation at run time.
// //
// Spec pseudocode definition: // Spec pseudocode definition:
// def is_aggregator(state: BeaconState, slot: Slot, index: CommitteeIndex, slot_signature: BLSSignature) -> bool: // def is_aggregator(state: BeaconState, slot: Slot, index: CommitteeIndex, slot_signature: BLSSignature) -> bool:
// committee = get_beacon_committee(state, slot, index) // committee = get_beacon_committee(state, slot, index)
// modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE) // modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE)
// return bytes_to_int(hash(slot_signature)[0:8]) % modulo == 0 // return bytes_to_int(hash(slot_signature)[0:8]) % modulo == 0
func IsAggregator(state *pb.BeaconState, slot uint64, index uint64, slotSig []byte) (bool, error) { func IsAggregator(committeeCount uint64, slot uint64, index uint64, slotSig []byte) (bool, error) {
committee, err := BeaconCommittee(state, slot, index)
if err != nil {
return false, err
}
modulo := uint64(1) modulo := uint64(1)
if len(committee)/int(params.BeaconConfig().TargetAggregatorsPerCommittee) > 1 { if committeeCount/params.BeaconConfig().TargetAggregatorsPerCommittee > 1 {
modulo = uint64(len(committee)) / params.BeaconConfig().TargetAggregatorsPerCommittee modulo = committeeCount / params.BeaconConfig().TargetAggregatorsPerCommittee
} }
b := hashutil.Hash(slotSig) b := hashutil.Hash(slotSig)

View File

@@ -228,8 +228,13 @@ func TestSlotSignature_Verify(t *testing.T) {
func TestIsAggregator_True(t *testing.T) { func TestIsAggregator_True(t *testing.T) {
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
committee, err := helpers.BeaconCommitteeFromState(beaconState, 0, 0)
if err != nil {
t.Fatal(err)
}
sig := privKeys[0].Sign([]byte{}, 0) sig := privKeys[0].Sign([]byte{}, 0)
agg, err := helpers.IsAggregator(beaconState, 0, 0, sig.Marshal()) agg, err := helpers.IsAggregator(uint64(len(committee)), 0, 0, sig.Marshal())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -243,8 +248,12 @@ func TestIsAggregator_False(t *testing.T) {
defer params.UseMainnetConfig() defer params.UseMainnetConfig()
beaconState, privKeys := testutil.DeterministicGenesisState(t, 2048) beaconState, privKeys := testutil.DeterministicGenesisState(t, 2048)
committee, err := helpers.BeaconCommitteeFromState(beaconState, 0, 0)
if err != nil {
t.Fatal(err)
}
sig := privKeys[0].Sign([]byte{}, 0) sig := privKeys[0].Sign([]byte{}, 0)
agg, err := helpers.IsAggregator(beaconState, 0, 0, sig.Marshal()) agg, err := helpers.IsAggregator(uint64(len(committee)), 0, 0, sig.Marshal())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -17,7 +17,12 @@ import (
var committeeCache = cache.NewCommitteesCache() var committeeCache = cache.NewCommitteesCache()
// CommitteeCountAtSlot returns the number of crosslink committees of a slot. // SlotCommitteeCount returns the number of crosslink committees of a slot. The
// active validator count is provided as an argument rather than a direct implementation
// from the spec definition. Having the active validator count as an argument allows for
// cheaper computation, instead of retrieving head state, one can retrieve the validator
// count.
//
// //
// Spec pseudocode definition: // Spec pseudocode definition:
// def get_committee_count_at_slot(state: BeaconState, slot: Slot) -> uint64: // def get_committee_count_at_slot(state: BeaconState, slot: Slot) -> uint64:
@@ -29,23 +34,22 @@ var committeeCache = cache.NewCommitteesCache()
// MAX_COMMITTEES_PER_SLOT, // MAX_COMMITTEES_PER_SLOT,
// len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, // len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE,
// )) // ))
func CommitteeCountAtSlot(state *pb.BeaconState, slot uint64) (uint64, error) { func SlotCommitteeCount(activeValidatorCount uint64) uint64 {
epoch := SlotToEpoch(slot) var committeePerSlot = activeValidatorCount / params.BeaconConfig().SlotsPerEpoch / params.BeaconConfig().TargetCommitteeSize
count, err := ActiveValidatorCount(state, epoch)
if err != nil {
return 0, errors.Wrap(err, "could not get active count")
}
var committeePerSlot = count / params.BeaconConfig().SlotsPerEpoch / params.BeaconConfig().TargetCommitteeSize
if committeePerSlot > params.BeaconConfig().MaxCommitteesPerSlot { if committeePerSlot > params.BeaconConfig().MaxCommitteesPerSlot {
return params.BeaconConfig().MaxCommitteesPerSlot, nil return params.BeaconConfig().MaxCommitteesPerSlot
} }
if committeePerSlot == 0 { if committeePerSlot == 0 {
return 1, nil return 1
} }
return committeePerSlot, nil
return committeePerSlot
} }
// BeaconCommittee returns the crosslink committee of a given slot and committee index. // BeaconCommitteeFromState returns the crosslink committee of a given slot and committee index. This
// is a spec implementation where state is used as an argument. In case of state retrieval
// becomes expensive, consider using BeaconCommittee below.
// //
// Spec pseudocode definition: // Spec pseudocode definition:
// def get_beacon_committee(state: BeaconState, slot: Slot, index: CommitteeIndex) -> Sequence[ValidatorIndex]: // def get_beacon_committee(state: BeaconState, slot: Slot, index: CommitteeIndex) -> Sequence[ValidatorIndex]:
@@ -61,15 +65,15 @@ func CommitteeCountAtSlot(state *pb.BeaconState, slot uint64) (uint64, error) {
// index=epoch_offset, // index=epoch_offset,
// count=committees_per_slot * SLOTS_PER_EPOCH, // count=committees_per_slot * SLOTS_PER_EPOCH,
// ) // )
func BeaconCommittee(state *pb.BeaconState, slot uint64, index uint64) ([]uint64, error) { func BeaconCommitteeFromState(state *pb.BeaconState, slot uint64, committeeIndex uint64) ([]uint64, error) {
epoch := SlotToEpoch(slot) epoch := SlotToEpoch(slot)
if featureconfig.Get().EnableNewCache { seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester) if err != nil {
if err != nil { return nil, errors.Wrap(err, "could not get seed")
return nil, errors.Wrap(err, "could not get seed") }
}
indices, err := committeeCache.Committee(slot, seed, index) if featureconfig.Get().EnableNewCache {
indices, err := committeeCache.Committee(slot, seed, committeeIndex)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not interface with committee cache") return nil, errors.Wrap(err, "could not interface with committee cache")
} }
@@ -78,30 +82,34 @@ func BeaconCommittee(state *pb.BeaconState, slot uint64, index uint64) ([]uint64
} }
} }
committeesPerSlot, err := CommitteeCountAtSlot(state, slot)
if err != nil {
return nil, errors.Wrap(err, "could not get committee count at slot")
}
epochOffset := index + (slot%params.BeaconConfig().SlotsPerEpoch)*committeesPerSlot
count := committeesPerSlot * params.BeaconConfig().SlotsPerEpoch
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
if err != nil {
return nil, errors.Wrap(err, "could not get seed")
}
indices, err := ActiveValidatorIndices(state, epoch) indices, err := ActiveValidatorIndices(state, epoch)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get active indices") return nil, errors.Wrap(err, "could not get active indices")
} }
return BeaconCommittee(indices, seed, slot, committeeIndex)
}
// BeaconCommittee returns the crosslink committee of a given slot and committee index. The
// validator indices and seed are provided as an argument rather than a direct implementation
// from the spec definition. Having them as an argument allows for cheaper computation run time.
func BeaconCommittee(validatorIndices []uint64, seed [32]byte, slot uint64, committeeIndex uint64) ([]uint64, error) {
if featureconfig.Get().EnableNewCache { if featureconfig.Get().EnableNewCache {
if err := UpdateCommitteeCache(state); err != nil { indices, err := committeeCache.Committee(slot, seed, committeeIndex)
return nil, errors.Wrap(err, "could not update committee cache") if err != nil {
return nil, errors.Wrap(err, "could not interface with committee cache")
}
if indices != nil {
return indices, nil
} }
} }
return ComputeCommittee(indices, seed, epochOffset, count) committeesPerSlot := SlotCommitteeCount(uint64(len(validatorIndices)))
epochOffset := committeeIndex + (slot%params.BeaconConfig().SlotsPerEpoch)*committeesPerSlot
count := committeesPerSlot * params.BeaconConfig().SlotsPerEpoch
return ComputeCommittee(validatorIndices, seed, epochOffset, count)
} }
// BeaconCommitteeWithoutCache returns the crosslink committee of a given slot and committee index without the // BeaconCommitteeWithoutCache returns the crosslink committee of a given slot and committee index without the
@@ -109,11 +117,11 @@ func BeaconCommittee(state *pb.BeaconState, slot uint64, index uint64) ([]uint64
// TODO(3603): Delete this function when issue 3603 closes. // TODO(3603): Delete this function when issue 3603 closes.
func BeaconCommitteeWithoutCache(state *pb.BeaconState, slot uint64, index uint64) ([]uint64, error) { func BeaconCommitteeWithoutCache(state *pb.BeaconState, slot uint64, index uint64) ([]uint64, error) {
epoch := SlotToEpoch(slot) epoch := SlotToEpoch(slot)
activeValidatorCount, err := ActiveValidatorCount(state, epoch)
committeesPerSlot, err := CommitteeCountAtSlot(state, slot)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get committee count at slot") return nil, err
} }
committeesPerSlot := SlotCommitteeCount(activeValidatorCount)
epochOffset := index + (slot%params.BeaconConfig().SlotsPerEpoch)*committeesPerSlot epochOffset := index + (slot%params.BeaconConfig().SlotsPerEpoch)*committeesPerSlot
count := committeesPerSlot * params.BeaconConfig().SlotsPerEpoch count := committeesPerSlot * params.BeaconConfig().SlotsPerEpoch
@@ -121,7 +129,6 @@ func BeaconCommitteeWithoutCache(state *pb.BeaconState, slot uint64, index uint6
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get seed") return nil, errors.Wrap(err, "could not get seed")
} }
indices, err := ActiveValidatorIndices(state, epoch) indices, err := ActiveValidatorIndices(state, epoch)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get active indices") return nil, errors.Wrap(err, "could not get active indices")
@@ -212,7 +219,7 @@ func CommitteeAssignments(state *pb.BeaconState, epoch uint64) (map[uint64]*Comm
if epoch > NextEpoch(state) { if epoch > NextEpoch(state) {
return nil, nil, fmt.Errorf( return nil, nil, fmt.Errorf(
"epoch %d can't be greater than next epoch %d", "epoch %d can't be greater than next epoch %d",
epoch, epoch,
NextEpoch(state), NextEpoch(state),
) )
} }
@@ -229,13 +236,13 @@ func CommitteeAssignments(state *pb.BeaconState, epoch uint64) (map[uint64]*Comm
proposerIndexToSlot[i] = slot proposerIndexToSlot[i] = slot
} }
// Each slot in an epoch has a different set of committees. This value is derived from the activeValidatorIndices, err := ActiveValidatorIndices(state, epoch)
// active validator set, which does not change.
numCommitteesPerSlot, err := CommitteeCountAtSlot(state, StartSlot(epoch))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// Each slot in an epoch has a different set of committees. This value is derived from the
// active validator set, which does not change.
numCommitteesPerSlot := SlotCommitteeCount(uint64(len(activeValidatorIndices)))
validatorIndexToCommittee := make(map[uint64]*CommitteeAssignmentContainer) validatorIndexToCommittee := make(map[uint64]*CommitteeAssignmentContainer)
// Compute all committees for all slots. // Compute all committees for all slots.
@@ -243,7 +250,7 @@ func CommitteeAssignments(state *pb.BeaconState, epoch uint64) (map[uint64]*Comm
// Compute committees. // Compute committees.
for j := uint64(0); j < numCommitteesPerSlot; j++ { for j := uint64(0); j < numCommitteesPerSlot; j++ {
slot := startSlot + i slot := startSlot + i
committee, err := BeaconCommittee(state, slot, j /*committee index*/) committee, err := BeaconCommitteeFromState(state, slot, j /*committee index*/)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -316,13 +323,14 @@ func CommitteeAssignment(
proposerIndexToSlot[i] = slot proposerIndexToSlot[i] = slot
} }
activeValidatorIndices, err := ActiveValidatorIndices(state, epoch)
if err != nil {
return nil, 0, 0, 0, err
}
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ { for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
countAtSlot, err := CommitteeCountAtSlot(state, slot) countAtSlot := SlotCommitteeCount(uint64(len(activeValidatorIndices)))
if err != nil {
return nil, 0, 0, 0, errors.Wrapf(err, "could not get committee count at slot %d", slot)
}
for i := uint64(0); i < countAtSlot; i++ { for i := uint64(0); i < countAtSlot; i++ {
committee, err := BeaconCommittee(state, slot, i) committee, err := BeaconCommitteeFromState(state, slot, i)
if err != nil { if err != nil {
return nil, 0, 0, 0, errors.Wrapf(err, "could not get crosslink committee at slot %d", slot) return nil, 0, 0, 0, errors.Wrapf(err, "could not get crosslink committee at slot %d", slot)
} }
@@ -350,8 +358,8 @@ func VerifyBitfieldLength(bf bitfield.Bitfield, committeeSize uint64) error {
// VerifyAttestationBitfieldLengths verifies that an attestations aggregation and custody bitfields are // VerifyAttestationBitfieldLengths verifies that an attestations aggregation and custody bitfields are
// a valid length matching the size of the committee. // a valid length matching the size of the committee.
func VerifyAttestationBitfieldLengths(bState *pb.BeaconState, att *ethpb.Attestation) error { func VerifyAttestationBitfieldLengths(state *pb.BeaconState, att *ethpb.Attestation) error {
committee, err := BeaconCommittee(bState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
return errors.Wrap(err, "could not retrieve beacon committees") return errors.Wrap(err, "could not retrieve beacon committees")
} }
@@ -406,10 +414,9 @@ func UpdateCommitteeCache(state *pb.BeaconState) error {
if err != nil { if err != nil {
return err return err
} }
count, err := CommitteeCountAtSlot(state, StartSlot(epoch))
if err != nil { count := SlotCommitteeCount(uint64(len(shuffledIndices)))
return err
}
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester) seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
if err != nil { if err != nil {
return err return err

View File

@@ -116,7 +116,8 @@ func TestAttestationParticipants_NoCommitteeCache(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
attestationData.Target = &ethpb.Checkpoint{Epoch: 0} attestationData.Target = &ethpb.Checkpoint{Epoch: 0}
attestationData.Slot = tt.attestationSlot attestationData.Slot = tt.attestationSlot
committee, err := BeaconCommittee(state, tt.attestationSlot, 0 /* committee index */)
committee, err := BeaconCommitteeFromState(state, tt.attestationSlot, 0 /* committee index */)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -210,7 +211,7 @@ func TestAttestationParticipants_EmptyBitfield(t *testing.T) {
} }
attestationData := &ethpb.AttestationData{Target: &ethpb.Checkpoint{}} attestationData := &ethpb.AttestationData{Target: &ethpb.Checkpoint{}}
committee, err := BeaconCommittee(state, attestationData.Slot, attestationData.CommitteeIndex) committee, err := BeaconCommitteeFromState(state, attestationData.Slot, attestationData.CommitteeIndex)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -394,7 +395,7 @@ func TestCommitteeAssignments_CanRetrieve(t *testing.T) {
state := &pb.BeaconState{ state := &pb.BeaconState{
Validators: validators, Validators: validators,
Slot: 2*params.BeaconConfig().SlotsPerEpoch, // epoch 2 Slot: 2 * params.BeaconConfig().SlotsPerEpoch, // epoch 2
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
} }

View File

@@ -610,7 +610,7 @@ func CanProcessEpoch(state *pb.BeaconState) bool {
func ProcessEpochPrecompute(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) { func ProcessEpochPrecompute(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessEpoch") ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessEpoch")
defer span.End() defer span.End()
span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.SlotToEpoch(state.Slot)))) span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.CurrentEpoch(state))))
vp, bp := precompute.New(ctx, state) vp, bp := precompute.New(ctx, state)
vp, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp) vp, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp)

View File

@@ -379,7 +379,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
blockAtt := &ethpb.Attestation{ blockAtt := &ethpb.Attestation{
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
Slot: beaconState.Slot - 1, Slot: beaconState.Slot - 1,
Target: &ethpb.Checkpoint{Epoch: helpers.SlotToEpoch(beaconState.Slot)}, Target: &ethpb.Checkpoint{Epoch: helpers.CurrentEpoch(beaconState)},
Source: &ethpb.Checkpoint{ Source: &ethpb.Checkpoint{
Epoch: 0, Epoch: 0,
Root: []byte("hello-world"), Root: []byte("hello-world"),
@@ -387,7 +387,8 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
AggregationBits: aggBits, AggregationBits: aggBits,
CustodyBits: custodyBits, CustodyBits: custodyBits,
} }
committee, err := helpers.BeaconCommittee(beaconState, blockAtt.Data.Slot, blockAtt.Data.CommitteeIndex)
committee, err := helpers.BeaconCommitteeFromState(beaconState, blockAtt.Data.Slot, blockAtt.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@@ -633,7 +634,7 @@ func BenchmarkProcessBlk_65536Validators_FullBlock(b *testing.B) {
// Precache the shuffled indices // Precache the shuffled indices
for i := uint64(0); i < committeeCount; i++ { for i := uint64(0); i < committeeCount; i++ {
if _, err := helpers.BeaconCommittee(s, 0, i); err != nil { if _, err := helpers.BeaconCommitteeFromState(s, 0, i); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
@@ -676,7 +677,7 @@ func TestProcessBlk_AttsBasedOnValidatorCount(t *testing.T) {
CustodyBits: custodyBits, CustodyBits: custodyBits,
} }
committee, err := helpers.BeaconCommittee(s, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(s, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@@ -39,7 +39,7 @@ func TestHandleAttestation_Saves_NewAttestation(t *testing.T) {
AggregationBits: bitfield.Bitlist{0xCF, 0xC0, 0xC0, 0xC0, 0x01}, AggregationBits: bitfield.Bitlist{0xCF, 0xC0, 0xC0, 0xC0, 0x01},
CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01}, CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01},
} }
committee, err := helpers.BeaconCommittee(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -138,9 +138,9 @@ func TestHandleAttestation_Aggregates_LargeNumValidators(t *testing.T) {
} }
// Next up, we compute the committee for the attestation we're testing. // Next up, we compute the committee for the attestation we're testing.
committee, err := helpers.BeaconCommittee(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
attDataRoot, err := ssz.HashTreeRoot(att.Data) attDataRoot, err := ssz.HashTreeRoot(att.Data)
if err != nil { if err != nil {
@@ -213,9 +213,9 @@ func TestHandleAttestation_Skips_PreviouslyAggregatedAttestations(t *testing.T)
CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01}, CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01},
} }
committee, err := helpers.BeaconCommittee(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
aggregationBits := bitfield.NewBitlist(uint64(len(committee))) aggregationBits := bitfield.NewBitlist(uint64(len(committee)))
aggregationBits.SetBitAt(0, true) aggregationBits.SetBitAt(0, true)
@@ -353,9 +353,9 @@ func TestRetrieveAttestations_OK(t *testing.T) {
AggregationBits: aggBits, AggregationBits: aggBits,
CustodyBits: custodyBits, CustodyBits: custodyBits,
} }
committee, err := helpers.BeaconCommittee(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
attestingIndices, err := helpers.AttestingIndices(att.AggregationBits, committee) attestingIndices, err := helpers.AttestingIndices(att.AggregationBits, committee)
if err != nil { if err != nil {

View File

@@ -8,7 +8,6 @@ go_library(
deps = [ deps = [
"//beacon-chain/blockchain:go_default_library", "//beacon-chain/blockchain:go_default_library",
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/db:go_default_library", "//beacon-chain/db:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",
"//proto/beacon/rpc/v1:go_default_library", "//proto/beacon/rpc/v1:go_default_library",

View File

@@ -5,7 +5,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db" "github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/sync" "github.com/prysmaticlabs/prysm/beacon-chain/sync"
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
@@ -40,21 +39,6 @@ func (as *Server) SubmitAggregateAndProof(ctx context.Context, req *pb.Aggregati
return nil, status.Errorf(codes.Unavailable, "Syncing to latest head, not ready to respond") return nil, status.Errorf(codes.Unavailable, "Syncing to latest head, not ready to respond")
} }
headState, err := as.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve head state: %v", err)
}
// Advance slots if it is behind the epoch start of requested slot.
// Ex: head slot is 100, req slot is 150, epoch start of 150 is 128. Advance 100 to 128.
reqEpochStartSlot := helpers.StartSlot(helpers.SlotToEpoch(req.Slot))
if reqEpochStartSlot > headState.Slot {
headState, err = state.ProcessSlots(ctx, headState, reqEpochStartSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", req.Slot, err)
}
}
validatorIndex, exists, err := as.BeaconDB.ValidatorIndex(ctx, bytesutil.ToBytes48(req.PublicKey)) validatorIndex, exists, err := as.BeaconDB.ValidatorIndex(ctx, bytesutil.ToBytes48(req.PublicKey))
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get validator index from DB: %v", err) return nil, status.Errorf(codes.Internal, "Could not get validator index from DB: %v", err)
@@ -63,8 +47,22 @@ func (as *Server) SubmitAggregateAndProof(ctx context.Context, req *pb.Aggregati
return nil, status.Error(codes.Internal, "Could not locate validator index in DB") return nil, status.Error(codes.Internal, "Could not locate validator index in DB")
} }
epoch := helpers.SlotToEpoch(req.Slot)
activeValidatorIndices, err := as.HeadFetcher.HeadValidatorsIndices(epoch)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get validators: %v", err)
}
seed, err := as.HeadFetcher.HeadSeed(epoch)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get seed: %v", err)
}
committee, err := helpers.BeaconCommittee(activeValidatorIndices, seed, req.Slot, req.CommitteeIndex)
if err != nil {
return nil, err
}
// Check if the validator is an aggregator // Check if the validator is an aggregator
isAggregator, err := helpers.IsAggregator(headState, req.Slot, req.CommitteeIndex, req.SlotSignature) isAggregator, err := helpers.IsAggregator(uint64(len(committee)), req.Slot, req.CommitteeIndex, req.SlotSignature)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get aggregator status: %v", err) return nil, status.Errorf(codes.Internal, "Could not get aggregator status: %v", err)
} }

View File

@@ -306,7 +306,7 @@ func BenchmarkCommitteeAssignment(b *testing.B) {
ctx := context.Background() ctx := context.Background()
genesis := blk.NewGenesisBlock([]byte{}) genesis := blk.NewGenesisBlock([]byte{})
depChainStart := uint64(8192*2) depChainStart := uint64(8192 * 2)
deposits, _, _ := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, _ := testutil.DeterministicDepositsAndKeys(depChainStart)
eth1Data, err := testutil.DeterministicEth1Data(len(deposits)) eth1Data, err := testutil.DeterministicEth1Data(len(deposits))
if err != nil { if err != nil {

View File

@@ -205,7 +205,7 @@ func generateAttesterSlashings(
attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings) attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings)
for i := uint64(0); i < numSlashings; i++ { for i := uint64(0); i < numSlashings; i++ {
committeeIndex := rand.Uint64() % params.BeaconConfig().MaxCommitteesPerSlot committeeIndex := rand.Uint64() % params.BeaconConfig().MaxCommitteesPerSlot
committee, err := helpers.BeaconCommittee(bState, bState.Slot, committeeIndex) committee, err := helpers.BeaconCommitteeFromState(bState, bState.Slot, committeeIndex)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -330,10 +330,11 @@ func GenerateAttestations(
} }
} }
committeesPerSlot, err := helpers.CommitteeCountAtSlot(bState, slot) activeValidatorCount, err := helpers.ActiveValidatorCount(bState, currentEpoch)
if err != nil { if err != nil {
return nil, err return nil, err
} }
committeesPerSlot := helpers.SlotCommitteeCount(activeValidatorCount)
if numToGen < committeesPerSlot { if numToGen < committeesPerSlot {
log.Printf( log.Printf(
@@ -361,7 +362,7 @@ func GenerateAttestations(
domain := helpers.Domain(bState.Fork, currentEpoch, params.BeaconConfig().DomainBeaconAttester) domain := helpers.Domain(bState.Fork, currentEpoch, params.BeaconConfig().DomainBeaconAttester)
for c := uint64(0); c < committeesPerSlot && c < numToGen; c++ { for c := uint64(0); c < committeesPerSlot && c < numToGen; c++ {
committee, err := helpers.BeaconCommittee(bState, slot, c) committee, err := helpers.BeaconCommitteeFromState(bState, slot, c)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -95,7 +95,7 @@ func main() {
} }
// Retrieve attestation indices // Retrieve attestation indices
for _, att := range atts { for _, att := range atts {
committee, err := helpers.BeaconCommittee(state, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
panic(err) panic(err)
} }