Prevent 0 value for committeesPerSlot in shuffle function (#648)

This commit is contained in:
Yutaro Mori
2018-10-13 14:05:19 +09:00
committed by GitHub
parent 6d0290664a
commit f767b11348
6 changed files with 49 additions and 24 deletions

View File

@@ -22,9 +22,9 @@ func ShuffleValidatorsToCommittees(seed common.Hash, activeValidators []*pb.Vali
// splitBySlotShard splits the validator list into evenly sized committees and assigns each
// committee to a slot and a shard. If the validator set is large, multiple committees are assigned
// to a single slot and shard. See getCommitteeParams for more details.
// to a single slot and shard. See getCommitteesPerSlot for more details.
func splitBySlotShard(shuffledValidators []uint32, crosslinkStartShard uint64) []*pb.ShardAndCommitteeArray {
committeesPerSlot := getCommitteeParams(len(shuffledValidators))
committeesPerSlot := getCommitteesPerSlot(len(shuffledValidators))
committeBySlotAndShard := []*pb.ShardAndCommitteeArray{}
@@ -51,16 +51,21 @@ func splitBySlotShard(shuffledValidators []uint32, crosslinkStartShard uint64) [
return committeBySlotAndShard
}
// getCommitteeParams calculates the parameters for ShuffleValidatorsToCommittees.
// If numActiveValidators > CycleLength * MinCommitteeSize, committees are based off a max amount
// from either numActiveValidators / CycleLength / MinCommitteeSize or
// it is decided from the ShardCount / CycleLength.
func getCommitteeParams(numActiveValidators int) (committeesPerSlot int) {
// getCommitteesPerSlot calculates the parameters for ShuffleValidatorsToCommittees.
// The minimum value for committeesPerSlot is 1.
// Otherwise, the value for committeesPerSlot is the smaller of
// numActiveValidators / CycleLength / (MinCommitteeSize*2) + 1 or
// ShardCount / CycleLength.
func getCommitteesPerSlot(numActiveValidators int) int {
cycleLength := int(params.GetConfig().CycleLength)
boundOnAVS := numActiveValidators/cycleLength/int(params.GetConfig().MinCommiteeSize*2) + 1
boundOnValidators := numActiveValidators/cycleLength/int(params.GetConfig().MinCommiteeSize*2) + 1
boundOnShardCount := params.GetConfig().ShardCount / cycleLength
if boundOnAVS > boundOnShardCount {
// Ensure that comitteesPerSlot is at least 1.
if boundOnShardCount == 0 {
return 1
} else if boundOnValidators > boundOnShardCount {
return boundOnShardCount
}
return boundOnAVS
return boundOnValidators
}

View File

@@ -99,33 +99,48 @@ func TestSmallSampleValidators(t *testing.T) {
}
}
func TestGetCommitteeParamsSmallValidatorSet(t *testing.T) {
func TestGetCommitteesPerSlotSmallValidatorSet(t *testing.T) {
numValidators := int(params.GetConfig().CycleLength * params.GetConfig().MinCommiteeSize / 4)
committesPerSlot := getCommitteeParams(numValidators)
committesPerSlot := getCommitteesPerSlot(numValidators)
if committesPerSlot != 1 {
t.Fatalf("Expected committeesPerSlot to equal %d: got %d", 1, committesPerSlot)
}
}
func TestGetCommitteeParamsRegularValidatorSet(t *testing.T) {
func TestGetCommitteesPerSlotRegularValidatorSet(t *testing.T) {
numValidators := int(params.GetConfig().CycleLength * params.GetConfig().MinCommiteeSize)
committesPerSlot := getCommitteeParams(numValidators)
committesPerSlot := getCommitteesPerSlot(numValidators)
if committesPerSlot != 1 {
t.Fatalf("Expected committeesPerSlot to equal %d: got %d", 1, committesPerSlot)
}
}
func TestGetCommitteeParamsLargeValidatorSet(t *testing.T) {
func TestGetCommitteesPerSlotLargeValidatorSet(t *testing.T) {
numValidators := int(params.GetConfig().CycleLength*params.GetConfig().MinCommiteeSize) * 8
committesPerSlot := getCommitteeParams(numValidators)
committesPerSlot := getCommitteesPerSlot(numValidators)
if committesPerSlot != 5 {
t.Fatalf("Expected committeesPerSlot to equal %d: got %d", 5, committesPerSlot)
}
}
func TestGetCommitteesPerSlotSmallShardCount(t *testing.T) {
config := params.GetConfig()
oldShardCount := config.ShardCount
config.ShardCount = int(config.CycleLength) - 1
numValidators := int(params.GetConfig().CycleLength * params.GetConfig().MinCommiteeSize)
committesPerSlot := getCommitteesPerSlot(numValidators)
if committesPerSlot != 1 {
t.Fatalf("Expected committeesPerSlot to equal %d: got %d", 1, committesPerSlot)
}
config.ShardCount = oldShardCount
}
func TestValidatorsBySlotShardRegularValidatorSet(t *testing.T) {
validatorIndices := []uint32{}
numValidators := int(params.GetConfig().CycleLength * params.GetConfig().MinCommiteeSize)

View File

@@ -58,7 +58,7 @@ var demoConfig = &Config{
GenesisTime: time.Now(),
ModuloBias: 16777216,
CycleLength: uint64(5),
ShardCount: 3,
ShardCount: 5,
Gwei: 1e9,
DepositSize: 32,
SlotDuration: uint64(8),

View File

@@ -323,17 +323,24 @@ func TestNewDynastyRecalculations(t *testing.T) {
}
}
func TestInitGenesisJsonFailure(t *testing.T) {
fname := "/genesis.json"
pwd, _ := os.Getwd()
fnamePath := pwd + fname
_, err := NewGenesisCrystallizedState(fnamePath)
if err == nil {
t.Fatalf("genesis.json should have failed %v", err)
}
}
func TestInitGenesisJson(t *testing.T) {
fname := "/genesis.json"
pwd, _ := os.Getwd()
fnamePath := pwd + fname
os.Remove(fnamePath)
_, err := NewGenesisCrystallizedState(fnamePath)
if err == nil {
t.Fatalf("genesis.json should have failed %v", err)
}
params.SetEnv("demo")
cStateJSON := &pb.CrystallizedState{
LastStateRecalculationSlot: 0,
JustifiedStreak: 1,

View File

@@ -111,7 +111,6 @@ func (s *Service) Stop() error {
// From this, the validator client can deduce what slot interval the beacon
// node is in and determine when exactly it is time to propose or attest.
func (s *Service) fetchCurrentAssignmentsAndGenesisTime(client pb.BeaconServiceClient) {
// Currently fetches assignments for all validators.
req := &pb.ValidatorAssignmentRequest{
AllValidators: true,

View File

@@ -190,7 +190,6 @@ func (s *ShardEthereum) registerTXPool() error {
// registerBeaconService registers a service that fetches streams from a beacon node
// via RPC.
func (s *ShardEthereum) registerBeaconService(pubKey []byte) error {
var rpcService *rpcclient.Service
if err := s.services.FetchService(&rpcService); err != nil {
return err