mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 16:08:26 -05:00
Move Get Cutoff Algo to Utils Package (#370)
This commit is contained in:
@@ -270,52 +270,6 @@ func (b *BeaconChain) getAttestersProposer(seed common.Hash) ([]int, int, error)
|
||||
return indices[:int(attesterCount)], indices[len(indices)-1], nil
|
||||
}
|
||||
|
||||
// GetCutoffs is used to split up validators into groups at the start
|
||||
// of every epoch. It determines at what height validators can make
|
||||
// attestations and crosslinks. It returns lists of cutoff indices.
|
||||
func GetCutoffs(validatorCount int) []int {
|
||||
var heightCutoff = []int{0}
|
||||
var heights []int
|
||||
var heightCount float64
|
||||
|
||||
// Skip heights if there's not enough validators to fill in a min sized committee.
|
||||
if validatorCount < params.EpochLength*params.MinCommiteeSize {
|
||||
heightCount = math.Floor(float64(validatorCount) / params.MinCommiteeSize)
|
||||
for i := 0; i < int(heightCount); i++ {
|
||||
heights = append(heights, (i*params.Cofactor)%params.EpochLength)
|
||||
}
|
||||
// Enough validators, fill in all the heights.
|
||||
} else {
|
||||
heightCount = params.EpochLength
|
||||
for i := 0; i < int(heightCount); i++ {
|
||||
heights = append(heights, i)
|
||||
}
|
||||
}
|
||||
|
||||
filled := 0
|
||||
appendHeight := false
|
||||
for i := 0; i < params.EpochLength-1; i++ {
|
||||
appendHeight = false
|
||||
for _, height := range heights {
|
||||
if i == height {
|
||||
appendHeight = true
|
||||
}
|
||||
}
|
||||
if appendHeight {
|
||||
filled++
|
||||
heightCutoff = append(heightCutoff, filled*validatorCount/int(heightCount))
|
||||
} else {
|
||||
heightCutoff = append(heightCutoff, heightCutoff[len(heightCutoff)-1])
|
||||
}
|
||||
}
|
||||
heightCutoff = append(heightCutoff, validatorCount)
|
||||
|
||||
// TODO: For the validators assigned to each height, split them up into
|
||||
// committees for different shards. Do not assign the last END_EPOCH_GRACE_PERIOD
|
||||
// heights in a epoch to any shards.
|
||||
return heightCutoff
|
||||
}
|
||||
|
||||
// calculateRewardsFFG adjusts validators balances by applying rewards or penalties
|
||||
// based on FFG incentive structure.
|
||||
func (b *BeaconChain) calculateRewardsFFG() error {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -419,49 +418,6 @@ func TestRotateValidatorSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCutOffValidatorSet(t *testing.T) {
|
||||
// Test scenario #1: Assume there's enough validators to fill in all the heights.
|
||||
validatorCount := params.EpochLength * params.MinCommiteeSize
|
||||
cutoffsValidators := GetCutoffs(validatorCount)
|
||||
|
||||
// The length of cutoff list should be 65. Since there is 64 heights per epoch,
|
||||
// it means during every height, a new set of 128 validators will form a committee.
|
||||
expectedCount := int(math.Ceil(float64(validatorCount)/params.MinCommiteeSize)) + 1
|
||||
if len(cutoffsValidators) != expectedCount {
|
||||
t.Errorf("Incorrect count for cutoffs validator. Wanted: %v, Got: %v", expectedCount, len(cutoffsValidators))
|
||||
}
|
||||
|
||||
// Verify each cutoff is an increment of MinCommiteeSize, it means 128 validators forms a
|
||||
// a committee and get to attest per height.
|
||||
count := 0
|
||||
for _, cutoff := range cutoffsValidators {
|
||||
if cutoff != count {
|
||||
t.Errorf("cutoffsValidators did not get 128 increment. Wanted: count, Got: %v", cutoff)
|
||||
}
|
||||
count += params.MinCommiteeSize
|
||||
}
|
||||
|
||||
// Test scenario #2: Assume there's not enough validators to fill in all the heights.
|
||||
validatorCount = 1000
|
||||
cutoffsValidators = unique(GetCutoffs(validatorCount))
|
||||
// With 1000 validators, we can't attest every height. Given min committee size is 128,
|
||||
// we can only attest 7 heights. round down 1000 / 128 equals to 7, means the length is 8.
|
||||
expectedCount = int(math.Ceil(float64(validatorCount) / params.MinCommiteeSize))
|
||||
if len(unique(cutoffsValidators)) != expectedCount {
|
||||
t.Errorf("Incorrect count for cutoffs validator. Wanted: %v, Got: %v", expectedCount, validatorCount/params.MinCommiteeSize)
|
||||
}
|
||||
|
||||
// Verify each cutoff is an increment of 142~143 (1000 / 7).
|
||||
count = 0
|
||||
for _, cutoff := range cutoffsValidators {
|
||||
num := count * validatorCount / (len(cutoffsValidators) - 1)
|
||||
if cutoff != num {
|
||||
t.Errorf("cutoffsValidators did not get correct increment. Wanted: %v, Got: %v", num, cutoff)
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsEpochTransition(t *testing.T) {
|
||||
beaconChain, db := startInMemoryBeaconChain(t)
|
||||
defer db.Close()
|
||||
@@ -658,19 +614,6 @@ func TestComputeValidatorRewardsAndPenalties(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to remove duplicates in a int slice.
|
||||
func unique(ints []int) []int {
|
||||
keys := make(map[int]bool)
|
||||
list := []int{}
|
||||
for _, int := range ints {
|
||||
if _, value := keys[int]; !value {
|
||||
keys[int] = true
|
||||
list = append(list, int)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// NewBlock is a helper method to create blocks with valid defaults.
|
||||
// For a generic block, use NewBlock(t, nil)
|
||||
func NewBlock(t *testing.T, b *pb.BeaconBlockResponse) *types.Block {
|
||||
|
||||
@@ -2,6 +2,7 @@ package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/params"
|
||||
@@ -35,3 +36,49 @@ func ShuffleIndices(seed common.Hash, validatorCount int) ([]int, error) {
|
||||
}
|
||||
return validatorList, nil
|
||||
}
|
||||
|
||||
// GetCutoffs is used to split up validators into groups at the start
|
||||
// of every epoch. It determines at what height validators can make
|
||||
// attestations and crosslinks. It returns lists of cutoff indices.
|
||||
func GetCutoffs(validatorCount int) []int {
|
||||
var heightCutoff = []int{0}
|
||||
var heights []int
|
||||
var heightCount float64
|
||||
|
||||
// Skip heights if there's not enough validators to fill in a min sized committee.
|
||||
if validatorCount < params.EpochLength*params.MinCommiteeSize {
|
||||
heightCount = math.Floor(float64(validatorCount) / params.MinCommiteeSize)
|
||||
for i := 0; i < int(heightCount); i++ {
|
||||
heights = append(heights, (i*params.Cofactor)%params.EpochLength)
|
||||
}
|
||||
// Enough validators, fill in all the heights.
|
||||
} else {
|
||||
heightCount = params.EpochLength
|
||||
for i := 0; i < int(heightCount); i++ {
|
||||
heights = append(heights, i)
|
||||
}
|
||||
}
|
||||
|
||||
filled := 0
|
||||
appendHeight := false
|
||||
for i := 0; i < params.EpochLength-1; i++ {
|
||||
appendHeight = false
|
||||
for _, height := range heights {
|
||||
if i == height {
|
||||
appendHeight = true
|
||||
}
|
||||
}
|
||||
if appendHeight {
|
||||
filled++
|
||||
heightCutoff = append(heightCutoff, filled*validatorCount/int(heightCount))
|
||||
} else {
|
||||
heightCutoff = append(heightCutoff, heightCutoff[len(heightCutoff)-1])
|
||||
}
|
||||
}
|
||||
heightCutoff = append(heightCutoff, validatorCount)
|
||||
|
||||
// TODO: For the validators assigned to each height, split them up into
|
||||
// committees for different shards. Do not assign the last END_EPOCH_GRACE_PERIOD
|
||||
// heights in a epoch to any shards.
|
||||
return heightCutoff
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -31,3 +32,60 @@ func TestShuffleIndices(t *testing.T) {
|
||||
t.Errorf("2 shuffled lists shouldn't be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCutOffValidatorSet(t *testing.T) {
|
||||
// Test scenario #1: Assume there's enough validators to fill in all the heights.
|
||||
validatorCount := params.EpochLength * params.MinCommiteeSize
|
||||
cutoffsValidators := GetCutoffs(validatorCount)
|
||||
|
||||
// The length of cutoff list should be 65. Since there is 64 heights per epoch,
|
||||
// it means during every height, a new set of 128 validators will form a committee.
|
||||
expectedCount := int(math.Ceil(float64(validatorCount)/params.MinCommiteeSize)) + 1
|
||||
if len(cutoffsValidators) != expectedCount {
|
||||
t.Errorf("Incorrect count for cutoffs validator. Wanted: %v, Got: %v", expectedCount, len(cutoffsValidators))
|
||||
}
|
||||
|
||||
// Verify each cutoff is an increment of MinCommiteeSize, it means 128 validators forms a
|
||||
// a committee and get to attest per height.
|
||||
count := 0
|
||||
for _, cutoff := range cutoffsValidators {
|
||||
if cutoff != count {
|
||||
t.Errorf("cutoffsValidators did not get 128 increment. Wanted: count, Got: %v", cutoff)
|
||||
}
|
||||
count += params.MinCommiteeSize
|
||||
}
|
||||
|
||||
// Test scenario #2: Assume there's not enough validators to fill in all the heights.
|
||||
validatorCount = 1000
|
||||
cutoffsValidators = unique(GetCutoffs(validatorCount))
|
||||
// With 1000 validators, we can't attest every height. Given min committee size is 128,
|
||||
// we can only attest 7 heights. round down 1000 / 128 equals to 7, means the length is 8.
|
||||
expectedCount = int(math.Ceil(float64(validatorCount) / params.MinCommiteeSize))
|
||||
if len(unique(cutoffsValidators)) != expectedCount {
|
||||
t.Errorf("Incorrect count for cutoffs validator. Wanted: %v, Got: %v", expectedCount, validatorCount/params.MinCommiteeSize)
|
||||
}
|
||||
|
||||
// Verify each cutoff is an increment of 142~143 (1000 / 7).
|
||||
count = 0
|
||||
for _, cutoff := range cutoffsValidators {
|
||||
num := count * validatorCount / (len(cutoffsValidators) - 1)
|
||||
if cutoff != num {
|
||||
t.Errorf("cutoffsValidators did not get correct increment. Wanted: %v, Got: %v", num, cutoff)
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to remove duplicates in a int slice.
|
||||
func unique(ints []int) []int {
|
||||
keys := make(map[int]bool)
|
||||
list := []int{}
|
||||
for _, int := range ints {
|
||||
if _, value := keys[int]; !value {
|
||||
keys[int] = true
|
||||
list = append(list, int)
|
||||
}
|
||||
}
|
||||
return list
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user