prysm-pulse/beacon-chain/casper/validator.go
2018-10-01 20:54:45 -04:00

187 lines
6.4 KiB
Go

package casper
import (
"bytes"
"fmt"
"github.com/prysmaticlabs/prysm/beacon-chain/params"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared"
)
const bitsInByte = 8
// ActiveValidatorIndices filters out active validators based on start and end dynasty
// and returns their indices in a list.
func ActiveValidatorIndices(validators []*pb.ValidatorRecord, dynasty uint64) []uint32 {
var indices []uint32
for i := 0; i < len(validators); i++ {
if validators[i].StartDynasty <= dynasty && dynasty < validators[i].EndDynasty {
indices = append(indices, uint32(i))
}
}
return indices
}
// ExitedValidatorIndices filters out exited validators based on start and end dynasty
// and returns their indices in a list.
func ExitedValidatorIndices(validators []*pb.ValidatorRecord, dynasty uint64) []uint32 {
var indices []uint32
for i := 0; i < len(validators); i++ {
if validators[i].StartDynasty < dynasty && validators[i].EndDynasty <= dynasty {
indices = append(indices, uint32(i))
}
}
return indices
}
// QueuedValidatorIndices filters out queued validators based on start and end dynasty
// and returns their indices in a list.
func QueuedValidatorIndices(validators []*pb.ValidatorRecord, dynasty uint64) []uint32 {
var indices []uint32
for i := 0; i < len(validators); i++ {
if validators[i].StartDynasty > dynasty {
indices = append(indices, uint32(i))
}
}
return indices
}
// GetShardAndCommitteesForSlot returns the attester set of a given slot.
func GetShardAndCommitteesForSlot(shardCommittees []*pb.ShardAndCommitteeArray, lastStateRecalc uint64, slot uint64) (*pb.ShardAndCommitteeArray, error) {
if lastStateRecalc < params.GetConfig().CycleLength {
lastStateRecalc = 0
} else {
lastStateRecalc = lastStateRecalc - params.GetConfig().CycleLength
}
lowerBound := lastStateRecalc
upperBound := lastStateRecalc + params.GetConfig().CycleLength*2
if !(slot >= lowerBound && slot < upperBound) {
return nil, fmt.Errorf("cannot return attester set of given slot, input slot %v has to be in between %v and %v",
slot,
lowerBound,
upperBound,
)
}
return shardCommittees[slot-lastStateRecalc], nil
}
// AreAttesterBitfieldsValid validates that the length of the attester bitfield matches the attester indices
// defined in the Crystallized State.
func AreAttesterBitfieldsValid(attestation *pb.AggregatedAttestation, attesterIndices []uint32) bool {
// Validate attester bit field has the correct length.
if shared.BitLength(len(attesterIndices)) != len(attestation.AttesterBitfield) {
log.Debugf("attestation has incorrect bitfield length. Found %v, expected %v",
len(attestation.AttesterBitfield), shared.BitLength(len(attesterIndices)))
return false
}
// Valid attestation can not have non-zero trailing bits.
lastBit := len(attesterIndices)
remainingBits := lastBit % bitsInByte
if remainingBits == 0 {
return true
}
for i := 0; i < bitsInByte-remainingBits; i++ {
if shared.CheckBit(attestation.AttesterBitfield, lastBit+i) {
log.Debugf("attestation has non-zero trailing bits")
return false
}
}
return true
}
// ProposerShardAndIndex returns the index and the shardID of a proposer from a given slot.
func ProposerShardAndIndex(shardCommittees []*pb.ShardAndCommitteeArray, lastStateRecalc uint64, slot uint64) (uint64, uint64, error) {
slotCommittees, err := GetShardAndCommitteesForSlot(
shardCommittees,
lastStateRecalc,
slot)
if err != nil {
return 0, 0, err
}
proposerShardID := slotCommittees.ArrayShardAndCommittee[0].ShardId
proposerIndex := slot % uint64(len(slotCommittees.ArrayShardAndCommittee[0].Committee))
return proposerShardID, proposerIndex, nil
}
// ValidatorIndex returns the index of the validator given an input public key.
func ValidatorIndex(pubKey []byte, dynasty uint64, validators []*pb.ValidatorRecord) (uint32, error) {
activeValidators := ActiveValidatorIndices(validators, dynasty)
for _, index := range activeValidators {
if bytes.Equal(validators[index].PublicKey, pubKey) {
return index, nil
}
}
return 0, fmt.Errorf("can't find validator index for public key %d", pubKey)
}
// ValidatorShardID returns the shard ID of the validator currently participates in.
func ValidatorShardID(pubKey []byte, dynasty uint64, validators []*pb.ValidatorRecord, shardCommittees []*pb.ShardAndCommitteeArray) (uint64, error) {
index, err := ValidatorIndex(pubKey, dynasty, validators)
if err != nil {
return 0, err
}
for _, slotCommittee := range shardCommittees {
for _, committee := range slotCommittee.ArrayShardAndCommittee {
for _, validator := range committee.Committee {
if validator == index {
return committee.ShardId, nil
}
}
}
}
return 0, fmt.Errorf("can't find shard ID for validator with public key %x", pubKey)
}
// ValidatorSlotAndResponsibility returns a validator's assingned slot number
// and whether it should act as an attester or proposer.
func ValidatorSlotAndResponsibility(pubKey []byte, dynasty uint64, validators []*pb.ValidatorRecord, shardCommittees []*pb.ShardAndCommitteeArray) (uint64, string, error) {
index, err := ValidatorIndex(pubKey, dynasty, validators)
if err != nil {
return 0, "", err
}
for slot, slotCommittee := range shardCommittees {
for i, committee := range slotCommittee.ArrayShardAndCommittee {
for v, validator := range committee.Committee {
if i == 0 && v == slot%len(committee.Committee) && validator == index {
return uint64(slot), "proposer", nil
}
if validator == index {
return uint64(slot), "attester", nil
}
}
}
}
return 0, "", fmt.Errorf("can't find slot number for validator with public key %d", pubKey)
}
// TotalActiveValidatorDeposit returns the total deposited amount in wei for all active validators.
func TotalActiveValidatorDeposit(dynasty uint64, validators []*pb.ValidatorRecord) uint64 {
var totalDeposit uint64
activeValidators := ActiveValidatorIndices(validators, dynasty)
for _, index := range activeValidators {
totalDeposit += validators[index].GetBalance()
}
return totalDeposit
}
// TotalActiveValidatorDepositInEth returns the total deposited amount in ETH for all active validators.
func TotalActiveValidatorDepositInEth(dynasty uint64, validators []*pb.ValidatorRecord) uint64 {
totalDeposit := TotalActiveValidatorDeposit(dynasty, validators)
depositInEth := totalDeposit / uint64(params.GetConfig().EtherDenomination)
return depositInEth
}