2018-08-09 18:25:48 +00:00
|
|
|
// Package utils defines utility functions for the beacon-chain.
|
2018-07-22 16:58:14 +00:00
|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2018-08-02 21:20:54 +00:00
|
|
|
"math"
|
2018-07-22 16:58:14 +00:00
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/params"
|
2018-07-28 19:53:02 +00:00
|
|
|
"golang.org/x/crypto/blake2b"
|
2018-07-22 16:58:14 +00:00
|
|
|
)
|
|
|
|
|
2018-07-23 15:43:41 +00:00
|
|
|
// ShuffleIndices returns a list of pseudorandomly sampled
|
2018-07-22 16:58:14 +00:00
|
|
|
// indices. This is used to use to select attesters and proposers.
|
|
|
|
func ShuffleIndices(seed common.Hash, validatorCount int) ([]int, error) {
|
|
|
|
if validatorCount > params.MaxValidators {
|
|
|
|
return nil, errors.New("Validator count has exceeded MaxValidator Count")
|
|
|
|
}
|
|
|
|
|
|
|
|
// construct a list of indices up to MaxValidators.
|
|
|
|
validatorList := make([]int, validatorCount)
|
|
|
|
for i := range validatorList {
|
|
|
|
validatorList[i] = i
|
|
|
|
}
|
|
|
|
|
2018-07-28 19:53:02 +00:00
|
|
|
hashSeed := blake2b.Sum256(seed[:])
|
2018-07-22 16:58:14 +00:00
|
|
|
|
|
|
|
// shuffle stops at the second to last index.
|
|
|
|
for i := 0; i < validatorCount-1; i++ {
|
|
|
|
// convert every 3 bytes to random number, replace validator index with that number.
|
2018-07-28 19:53:02 +00:00
|
|
|
for j := 0; j+3 < len(hashSeed); j += 3 {
|
|
|
|
swapNum := int(hashSeed[j] + hashSeed[j+1] + hashSeed[j+2])
|
2018-07-22 16:58:14 +00:00
|
|
|
remaining := validatorCount - i
|
|
|
|
swapPos := swapNum%remaining + i
|
|
|
|
validatorList[i], validatorList[swapPos] = validatorList[swapPos], validatorList[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return validatorList, nil
|
|
|
|
}
|
2018-08-02 21:20:54 +00:00
|
|
|
|
|
|
|
// GetCutoffs is used to split up validators into groups at the start
|
|
|
|
// of every epoch. It determines at what height validators can make
|
2018-08-09 22:54:59 +00:00
|
|
|
// attestations and crosslinks. It returns lists of cutoff indices and heights.
|
|
|
|
func GetCutoffs(validatorCount int) ([]int, []int) {
|
2018-08-02 21:20:54 +00:00
|
|
|
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.
|
2018-08-09 22:54:59 +00:00
|
|
|
return heightCutoff, heights
|
2018-08-02 21:20:54 +00:00
|
|
|
}
|