mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Implemented Rest of Epoch Helpers (#1145)
* beginning epoch processing helper funcs * renamed helpers to under epoch_operations * implemented AttestingValidatorIndices * deleted old epoch_processing.go file * implemented WinningRoot & LowerThan helper funcs * rest of the epoch helpers * gazelle * added tests * merged * mentioned LowerThan is for big endian format * fixed spelling
This commit is contained in:
parent
1065617087
commit
b9a233da7d
@ -2,19 +2,21 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["epoch_processing.go"],
|
||||
srcs = ["epoch_operations.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytes:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["epoch_processing_test.go"],
|
||||
srcs = ["epoch_operations_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
|
338
beacon-chain/core/epoch/epoch_operations.go
Normal file
338
beacon-chain/core/epoch/epoch_operations.go
Normal file
@ -0,0 +1,338 @@
|
||||
package epoch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
block "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
b "github.com/prysmaticlabs/prysm/shared/bytes"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// Attestations returns the pending attestations of slots in the epoch
|
||||
// (state.slot-EPOCH_LENGTH...state.slot-1), not attestations that got
|
||||
// included in the chain during the epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in state.latest_attestations
|
||||
// if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]
|
||||
func Attestations(state *pb.BeaconState) []*pb.PendingAttestationRecord {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var thisEpochAttestations []*pb.PendingAttestationRecord
|
||||
var earliestSlot uint64
|
||||
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
|
||||
// If the state slot is less than epochLength, then the earliestSlot would
|
||||
// result in a negative number. Therefore we should default to
|
||||
// earliestSlot = 0 in this case.
|
||||
if state.Slot > epochLength {
|
||||
earliestSlot = state.Slot - epochLength
|
||||
}
|
||||
|
||||
if earliestSlot <= attestation.GetData().GetSlot() && attestation.GetData().GetSlot() < state.Slot {
|
||||
thisEpochAttestations = append(thisEpochAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return thisEpochAttestations
|
||||
}
|
||||
|
||||
// BoundaryAttestations returns the pending attestations from
|
||||
// the epoch's boundary block.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in this_epoch_attestations if a.data.epoch_boundary_root ==
|
||||
// get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot ==
|
||||
// state.justified_slot]
|
||||
func BoundaryAttestations(
|
||||
state *pb.BeaconState,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
) ([]*pb.PendingAttestationRecord, error) {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var boundaryAttestations []*pb.PendingAttestationRecord
|
||||
|
||||
for _, attestation := range thisEpochAttestations {
|
||||
|
||||
boundaryBlockRoot, err := block.BlockRoot(state, state.Slot-epochLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestationData := attestation.GetData()
|
||||
sameRoot := bytes.Equal(attestationData.JustifiedBlockRootHash32, boundaryBlockRoot)
|
||||
sameSlotNum := attestationData.JustifiedSlot == state.JustifiedSlot
|
||||
if sameRoot && sameSlotNum {
|
||||
boundaryAttestations = append(boundaryAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return boundaryAttestations, nil
|
||||
}
|
||||
|
||||
// PrevAttestations returns the attestations of the previous epoch
|
||||
// (state.slot - 2 * EPOCH_LENGTH...state.slot - EPOCH_LENGTH).
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in state.latest_attestations
|
||||
// if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]
|
||||
func PrevAttestations(state *pb.BeaconState) []*pb.PendingAttestationRecord {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var prevEpochAttestations []*pb.PendingAttestationRecord
|
||||
var earliestSlot uint64
|
||||
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
|
||||
// If the state slot is less than 2 * epochLength, then the earliestSlot would
|
||||
// result in a negative number. Therefore we should default to
|
||||
// earliestSlot = 0 in this case.
|
||||
if state.Slot > 2*epochLength {
|
||||
earliestSlot = state.Slot - 2*epochLength
|
||||
}
|
||||
|
||||
if earliestSlot <= attestation.GetData().GetSlot() &&
|
||||
attestation.GetData().GetSlot() < state.Slot-epochLength {
|
||||
prevEpochAttestations = append(prevEpochAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return prevEpochAttestations
|
||||
}
|
||||
|
||||
// PrevJustifiedAttestations returns the justified attestations
|
||||
// of the previous 2 epochs.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in this_epoch_attestations + previous_epoch_attestations
|
||||
// if a.justified_slot == state.previous_justified_slot]
|
||||
func PrevJustifiedAttestations(
|
||||
state *pb.BeaconState,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord,
|
||||
) []*pb.PendingAttestationRecord {
|
||||
|
||||
var prevJustifiedAttestations []*pb.PendingAttestationRecord
|
||||
epochAttestations := append(thisEpochAttestations, prevEpochAttestations...)
|
||||
|
||||
for _, attestation := range epochAttestations {
|
||||
if attestation.GetData().GetJustifiedSlot() == state.PreviousJustifiedSlot {
|
||||
prevJustifiedAttestations = append(prevJustifiedAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return prevJustifiedAttestations
|
||||
}
|
||||
|
||||
// PrevHeadAttestations returns the pending attestations from
|
||||
// the canonical beacon chain.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in previous_epoch_attestations
|
||||
// if a.beacon_block_root == get_block_root(state, a.slot)]
|
||||
func PrevHeadAttestations(
|
||||
state *pb.BeaconState,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord,
|
||||
) ([]*pb.PendingAttestationRecord, error) {
|
||||
|
||||
var headAttestations []*pb.PendingAttestationRecord
|
||||
for _, attestation := range prevEpochAttestations {
|
||||
canonicalBlockRoot, err := block.BlockRoot(state, attestation.GetData().GetSlot())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestationData := attestation.GetData()
|
||||
if bytes.Equal(attestationData.BeaconBlockRootHash32, canonicalBlockRoot) {
|
||||
headAttestations = append(headAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return headAttestations, nil
|
||||
}
|
||||
|
||||
// WinningRoot returns the shard block root with the most combined validator
|
||||
// effective balance. The ties broken by favoring lower shard block root values.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let winning_root(shard_committee) be equal to the value of shard_block_root
|
||||
// such that sum([get_effective_balance(state, i)
|
||||
// for i in attesting_validator_indices(shard_committee, shard_block_root)])
|
||||
// is maximized (ties broken by favoring lower shard_block_root values)
|
||||
func WinningRoot(
|
||||
state *pb.BeaconState,
|
||||
shardCommittee *pb.ShardAndCommittee,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord) ([]byte, error) {
|
||||
|
||||
var winnerBalance uint64
|
||||
var winnerRoot []byte
|
||||
var candidateRoots [][]byte
|
||||
attestations := append(thisEpochAttestations, prevEpochAttestations...)
|
||||
|
||||
for _, attestation := range attestations {
|
||||
if attestation.Data.Shard == shardCommittee.Shard {
|
||||
candidateRoots = append(candidateRoots, attestation.Data.ShardBlockRootHash32)
|
||||
}
|
||||
}
|
||||
|
||||
for _, candidateRoot := range candidateRoots {
|
||||
indices, err := validators.AttestingValidatorIndices(
|
||||
state,
|
||||
shardCommittee,
|
||||
candidateRoot,
|
||||
thisEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attesting validator indices: %v", err)
|
||||
}
|
||||
|
||||
var rootBalance uint64
|
||||
for _, index := range indices {
|
||||
rootBalance += validators.EffectiveBalance(state, index)
|
||||
}
|
||||
|
||||
if rootBalance > winnerBalance ||
|
||||
(rootBalance == winnerBalance && b.LowerThan(candidateRoot, winnerRoot)) {
|
||||
winnerBalance = rootBalance
|
||||
winnerRoot = candidateRoot
|
||||
}
|
||||
}
|
||||
return winnerRoot, nil
|
||||
}
|
||||
|
||||
// AttestingValidators returns the validators of the winning root.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let `attesting_validators(shard_committee)` be equal to
|
||||
// `attesting_validator_indices(shard_committee, winning_root(shard_committee))` for convenience
|
||||
func AttestingValidators(
|
||||
state *pb.BeaconState,
|
||||
shardCommittee *pb.ShardAndCommittee,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord) ([]uint32, error) {
|
||||
|
||||
root, err := WinningRoot(
|
||||
state,
|
||||
shardCommittee,
|
||||
thisEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get winning root: %v", err)
|
||||
}
|
||||
|
||||
indices, err := validators.AttestingValidatorIndices(
|
||||
state,
|
||||
shardCommittee,
|
||||
root,
|
||||
thisEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attesting validator indices: %v", err)
|
||||
}
|
||||
|
||||
return indices, nil
|
||||
}
|
||||
|
||||
// TotalAttestingBalance returns the total balance at stake of the validators
|
||||
// attested to the winning root.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let total_balance(shard_committee) =
|
||||
// sum([get_effective_balance(state, i) for i in shard_committee.committee])
|
||||
func TotalAttestingBalance(
|
||||
state *pb.BeaconState,
|
||||
shardCommittee *pb.ShardAndCommittee,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord) (uint64, error) {
|
||||
|
||||
var totalBalance uint64
|
||||
attestedValidatorIndices, err := AttestingValidators(state, shardCommittee, thisEpochAttestations, prevEpochAttestations)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not get attesting validator indices: %v", err)
|
||||
}
|
||||
|
||||
for _, index := range attestedValidatorIndices {
|
||||
totalBalance += validators.EffectiveBalance(state, index)
|
||||
}
|
||||
|
||||
return totalBalance, nil
|
||||
}
|
||||
|
||||
// TotalBalance returns the total balance at stake of the validators
|
||||
// from the shard committee regardless of validators attested or not.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let total_balance(shard_committee) =
|
||||
// sum([get_effective_balance(state, i) for i in shard_committee.committee])
|
||||
func TotalBalance(
|
||||
state *pb.BeaconState,
|
||||
shardCommittee *pb.ShardAndCommittee) uint64 {
|
||||
|
||||
var totalBalance uint64
|
||||
for _, index := range shardCommittee.Committee {
|
||||
totalBalance += validators.EffectiveBalance(state, index)
|
||||
}
|
||||
|
||||
return totalBalance
|
||||
}
|
||||
|
||||
// InclusionSlot returns the slot number of when the validator's
|
||||
// attestation gets included in the beacon chain.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let inclusion_slot(state, index) =
|
||||
// a.slot_included for the attestation a where index is in
|
||||
// get_attestation_participants(state, a.data, a.participation_bitfield)
|
||||
func InclusionSlot(state *pb.BeaconState, validatorIndex uint32) (uint64, error) {
|
||||
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
participatedValidators, err := validators.AttestationParticipants(state, attestation.Data, attestation.ParticipationBitfield)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not get attestation participants: %v", err)
|
||||
}
|
||||
|
||||
for _, index := range participatedValidators {
|
||||
if index == validatorIndex {
|
||||
return attestation.SlotIncluded, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("could not find inclusion slot for validator index %d", validatorIndex)
|
||||
}
|
||||
|
||||
// InclusionDistance returns the difference in slot number of when attestation
|
||||
// gets submitted and when it gets included.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let inclusion_distance(state, index) =
|
||||
// a.slot_included - a.data.slot where a is the above attestation same as
|
||||
// inclusion_slot
|
||||
func InclusionDistance(state *pb.BeaconState, validatorIndex uint32) (uint64, error) {
|
||||
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
participatedValidators, err := validators.AttestationParticipants(state, attestation.Data, attestation.ParticipationBitfield)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not get attestation participants: %v", err)
|
||||
}
|
||||
|
||||
for _, index := range participatedValidators {
|
||||
if index == validatorIndex {
|
||||
return attestation.SlotIncluded - attestation.Data.Slot, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("could not find inclusion distance for validator index %d", validatorIndex)
|
||||
}
|
||||
|
||||
// AdjustForInclusionDistance returns the calculated reward based on
|
||||
// how long it took for attestation to get included. The longer, the lower
|
||||
// the the reward.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def adjust_for_inclusion_distance(magnitude: int, distance: int) -> int:
|
||||
// """
|
||||
// Adjusts the reward of an attestation based on how long it took to get included
|
||||
// (the longer, the lower the reward). Returns a value between ``0`` and ``magnitude``.
|
||||
// ""
|
||||
// return magnitude // 2 + (magnitude // 2) * MIN_ATTESTATION_INCLUSION_DELAY // distance
|
||||
func AdjustForInclusionDistance(magniture uint64, distance uint64) uint64 {
|
||||
return magniture/2 + (magniture/2)*
|
||||
params.BeaconConfig().MinAttestationInclusionDelay/distance
|
||||
}
|
660
beacon-chain/core/epoch/epoch_operations_test.go
Normal file
660
beacon-chain/core/epoch/epoch_operations_test.go
Normal file
@ -0,0 +1,660 @@
|
||||
package epoch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestEpochAttestations(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var pendingAttestations []*pb.PendingAttestationRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
|
||||
pendingAttestations = append(pendingAttestations, &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: i,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{LatestAttestations: pendingAttestations}
|
||||
|
||||
tests := []struct {
|
||||
stateSlot uint64
|
||||
firstAttestationSlot uint64
|
||||
}{
|
||||
{
|
||||
stateSlot: 10,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 63,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 64,
|
||||
firstAttestationSlot: 64 - params.BeaconConfig().EpochLength,
|
||||
}, {
|
||||
stateSlot: 127,
|
||||
firstAttestationSlot: 127 - params.BeaconConfig().EpochLength,
|
||||
}, {
|
||||
stateSlot: 128,
|
||||
firstAttestationSlot: 128 - params.BeaconConfig().EpochLength,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot
|
||||
|
||||
if Attestations(state)[0].GetData().GetSlot() != tt.firstAttestationSlot {
|
||||
t.Errorf(
|
||||
"Result slot was an unexpected value. Wanted %d, got %d",
|
||||
tt.firstAttestationSlot,
|
||||
Attestations(state)[0].GetData().GetSlot(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEpochBoundaryAttestations(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
epochAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{0}, JustifiedSlot: 0}},
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{1}, JustifiedSlot: 1}},
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{2}, JustifiedSlot: 2}},
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{3}, JustifiedSlot: 3}},
|
||||
}
|
||||
|
||||
var latestBlockRootHash [][]byte
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength; i++ {
|
||||
latestBlockRootHash = append(latestBlockRootHash, []byte{byte(i)})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
LatestAttestations: epochAttestations,
|
||||
Slot: params.BeaconConfig().EpochLength,
|
||||
LatestBlockRootHash32S: [][]byte{},
|
||||
}
|
||||
|
||||
epochBoundaryAttestation, err := BoundaryAttestations(state, epochAttestations)
|
||||
if err == nil {
|
||||
t.Fatalf("EpochBoundaryAttestations should have failed with empty block root hash")
|
||||
}
|
||||
|
||||
state.LatestBlockRootHash32S = latestBlockRootHash
|
||||
epochBoundaryAttestation, err = BoundaryAttestations(state, epochAttestations)
|
||||
if err != nil {
|
||||
t.Fatalf("EpochBoundaryAttestations failed: %v", err)
|
||||
}
|
||||
|
||||
if epochBoundaryAttestation[0].GetData().GetJustifiedSlot() != 0 {
|
||||
t.Errorf("Wanted justified slot 0 for epoch boundary attestation, got: %d", epochBoundaryAttestation[0].GetData().GetJustifiedSlot())
|
||||
}
|
||||
|
||||
if !bytes.Equal(epochBoundaryAttestation[0].GetData().GetJustifiedBlockRootHash32(), []byte{0}) {
|
||||
t.Errorf("Wanted justified block hash [0] for epoch boundary attestation, got: %v",
|
||||
epochBoundaryAttestation[0].GetData().GetJustifiedBlockRootHash32())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevEpochAttestations(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var pendingAttestations []*pb.PendingAttestationRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*4; i++ {
|
||||
pendingAttestations = append(pendingAttestations, &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: i,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{LatestAttestations: pendingAttestations}
|
||||
|
||||
tests := []struct {
|
||||
stateSlot uint64
|
||||
firstAttestationSlot uint64
|
||||
}{
|
||||
{
|
||||
stateSlot: 10,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 127,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 383,
|
||||
firstAttestationSlot: 383 - 2*params.BeaconConfig().EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 129,
|
||||
firstAttestationSlot: 129 - 2*params.BeaconConfig().EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 256,
|
||||
firstAttestationSlot: 256 - 2*params.BeaconConfig().EpochLength,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot
|
||||
|
||||
if PrevAttestations(state)[0].GetData().GetSlot() != tt.firstAttestationSlot {
|
||||
t.Errorf(
|
||||
"Result slot was an unexpected value. Wanted %d, got %d",
|
||||
tt.firstAttestationSlot,
|
||||
Attestations(state)[0].GetData().GetSlot(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevJustifiedAttestations(t *testing.T) {
|
||||
prevEpochAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 0}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 2}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 5}},
|
||||
{Data: &pb.AttestationData{Shard: 2, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{Shard: 3, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 999}},
|
||||
}
|
||||
|
||||
thisEpochAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 0}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 10}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 15}},
|
||||
{Data: &pb.AttestationData{Shard: 0, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{Shard: 1, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 888}},
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{PreviousJustifiedSlot: 100}
|
||||
|
||||
prevJustifiedAttestations := PrevJustifiedAttestations(state, thisEpochAttestations, prevEpochAttestations)
|
||||
|
||||
for i, attestation := range prevJustifiedAttestations {
|
||||
if attestation.GetData().Shard != uint64(i) {
|
||||
t.Errorf("Wanted shard %d, got %d", i, attestation.GetData().Shard)
|
||||
}
|
||||
if attestation.GetData().GetJustifiedSlot() != 100 {
|
||||
t.Errorf("Wanted justified slot 100, got %d", attestation.GetData().GetJustifiedSlot())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadAttestations_Ok(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
prevAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: 1, BeaconBlockRootHash32: []byte{'A'}}},
|
||||
{Data: &pb.AttestationData{Slot: 2, BeaconBlockRootHash32: []byte{'B'}}},
|
||||
{Data: &pb.AttestationData{Slot: 3, BeaconBlockRootHash32: []byte{'C'}}},
|
||||
{Data: &pb.AttestationData{Slot: 4, BeaconBlockRootHash32: []byte{'D'}}},
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{Slot: 5, LatestBlockRootHash32S: [][]byte{{'A'}, {'X'}, {'C'}, {'Y'}}}
|
||||
|
||||
headAttestations, err := PrevHeadAttestations(state, prevAttestations)
|
||||
if err != nil {
|
||||
t.Fatalf("PrevHeadAttestations failed with %v", err)
|
||||
}
|
||||
|
||||
if headAttestations[0].GetData().GetSlot() != 1 {
|
||||
t.Errorf("headAttestations[0] wanted slot 1, got slot %d", headAttestations[0].GetData().GetSlot())
|
||||
}
|
||||
if headAttestations[1].GetData().GetSlot() != 3 {
|
||||
t.Errorf("headAttestations[1] wanted slot 3, got slot %d", headAttestations[1].GetData().GetSlot())
|
||||
}
|
||||
if !bytes.Equal([]byte{'A'}, headAttestations[0].GetData().GetBeaconBlockRootHash32()) {
|
||||
t.Errorf("headAttestations[0] wanted hash [A], got slot %v",
|
||||
headAttestations[0].GetData().GetBeaconBlockRootHash32())
|
||||
}
|
||||
if !bytes.Equal([]byte{'C'}, headAttestations[1].GetData().GetBeaconBlockRootHash32()) {
|
||||
t.Errorf("headAttestations[1] wanted hash [C], got slot %v",
|
||||
headAttestations[1].GetData().GetBeaconBlockRootHash32())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadAttestations_NotOk(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
prevAttestations := []*pb.PendingAttestationRecord{{Data: &pb.AttestationData{Slot: 1}}}
|
||||
|
||||
state := &pb.BeaconState{Slot: 0}
|
||||
|
||||
if _, err := PrevHeadAttestations(state, prevAttestations); err == nil {
|
||||
t.Fatal("PrevHeadAttestations should have failed with invalid range")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinningRoot_Ok(t *testing.T) {
|
||||
defaultBalance := params.BeaconConfig().MaxDeposit
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{0, 1, 2, 3, 4, 5, 6, 7}},
|
||||
}}}
|
||||
|
||||
// Assign 32 ETH balance to every validator in shardAndCommittees.
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
ValidatorBalances: []uint64{
|
||||
defaultBalance, defaultBalance, defaultBalance, defaultBalance,
|
||||
defaultBalance, defaultBalance, defaultBalance, defaultBalance,
|
||||
},
|
||||
}
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 0,
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
// Validator 1 and 7 attested to all 10 roots.
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
|
||||
// Since all 10 roots have the balance of 64 ETHs
|
||||
// WinningRoot chooses the lowest hash: []byte{100}
|
||||
winnerRoot, err := WinningRoot(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute WinningRoot: %v", err)
|
||||
}
|
||||
if !bytes.Equal(winnerRoot, []byte{100}) {
|
||||
t.Errorf("Incorrect winner root, wanted:[100], got: %v", winnerRoot)
|
||||
}
|
||||
|
||||
// Give root [105] one more attester
|
||||
attestations[5].ParticipationBitfield = []byte{'C'}
|
||||
winnerRoot, err = WinningRoot(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute WinningRoot: %v", err)
|
||||
}
|
||||
if !bytes.Equal(winnerRoot, []byte{105}) {
|
||||
t.Errorf("Incorrect winner root, wanted:[105], got: %v", winnerRoot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinningRoot_OutOfBound(t *testing.T) {
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
}
|
||||
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{},
|
||||
},
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
}
|
||||
|
||||
_, err := WinningRoot(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
[]*pb.PendingAttestationRecord{attestation},
|
||||
nil)
|
||||
if err == nil {
|
||||
t.Fatal("WinningRoot should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidators_Ok(t *testing.T) {
|
||||
defaultBalance := params.BeaconConfig().MaxDeposit
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{0, 1, 2, 3, 4, 5, 6, 7}},
|
||||
}}}
|
||||
|
||||
// Assign 32 ETH balance to every validator in shardAndCommittees.
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
ValidatorBalances: []uint64{
|
||||
defaultBalance, defaultBalance, defaultBalance, defaultBalance,
|
||||
defaultBalance, defaultBalance, defaultBalance, defaultBalance,
|
||||
},
|
||||
}
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 0,
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
// Validator 1 and 7 attested to the above roots.
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
|
||||
attestedValidators, err := AttestingValidators(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute WinningRoot: %v", err)
|
||||
}
|
||||
|
||||
// Verify the winner root is attested by validator 1 and 7.
|
||||
if !reflect.DeepEqual(attestedValidators, []uint32{1, 7}) {
|
||||
t.Errorf("Active validators don't match. Wanted:[1,7], Got: %v", attestedValidators)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidators_CantGetWinningRoot(t *testing.T) {
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
}
|
||||
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{},
|
||||
},
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
}
|
||||
|
||||
_, err := AttestingValidators(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
[]*pb.PendingAttestationRecord{attestation},
|
||||
nil)
|
||||
if err == nil {
|
||||
t.Fatal("AttestingValidators should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalAttestingBalance_Ok(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{0, 1, 2, 3, 4, 5, 6, 7}},
|
||||
}}}
|
||||
|
||||
// Assign validators to different balances.
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
ValidatorBalances: []uint64{16 * 1e9, 18 * 1e9, 20 * 1e9, 31 * 1e9,
|
||||
32 * 1e9, 34 * 1e9, 50 * 1e9, 50 * 1e9},
|
||||
}
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestationRecord
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 0,
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
// All validators attested to the above roots.
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
|
||||
attestedBalance, err := TotalAttestingBalance(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute TotalAttestingBalance: %v", err)
|
||||
}
|
||||
|
||||
// Verify the Attested balances are 16+18+20+31+(32*4)=213.
|
||||
if attestedBalance != 213*1e9 {
|
||||
t.Errorf("Incorrect attested balance. Wanted:231*1e9, Got: %d", attestedBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalAttestingBalance_NotOfBound(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
}
|
||||
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{},
|
||||
},
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
}
|
||||
|
||||
_, err := TotalAttestingBalance(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
[]*pb.PendingAttestationRecord{attestation},
|
||||
nil)
|
||||
if err == nil {
|
||||
t.Fatal("TotalAttestingBalance should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalBalance(t *testing.T) {
|
||||
|
||||
shardAndCommittees := &pb.ShardAndCommittee{Shard: 1, Committee: []uint32{0, 1, 2, 3, 4, 5, 6, 7}}
|
||||
|
||||
// Assign validators to different balances.
|
||||
state := &pb.BeaconState{
|
||||
Slot: 5,
|
||||
ValidatorBalances: []uint64{20 * 1e9, 25 * 1e9, 30 * 1e9, 30 * 1e9,
|
||||
32 * 1e9, 34 * 1e9, 50 * 1e9, 50 * 1e9},
|
||||
}
|
||||
|
||||
// 20 + 25 + 30 + 30 + 32 + 32 + 32 + 32 = 233
|
||||
totalBalance := TotalBalance(state, shardAndCommittees)
|
||||
if totalBalance != 233*1e9 {
|
||||
t.Errorf("Incorrect total balance. Wanted: 233*1e9, got: %d", totalBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionSlot_Ok(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{0, 1, 2, 3, 4, 5, 6, 7}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
// Validator 1 and 7 participated.
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
SlotIncluded: 100},
|
||||
},
|
||||
}
|
||||
|
||||
slot, err := InclusionSlot(state, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute InclusionSlot: %v", err)
|
||||
}
|
||||
|
||||
// validator 7's attestation got included in slot 100.
|
||||
if slot != 100 {
|
||||
t.Errorf("Incorrect slot. Wanted: 100, got: %d", slot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionSlot_BadBitfield(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{1}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
ParticipationBitfield: []byte{},
|
||||
SlotIncluded: 9},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := InclusionSlot(state, 1)
|
||||
if err == nil {
|
||||
t.Fatal("InclusionSlot should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionSlot_NotFound(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{1}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
}
|
||||
|
||||
_, err := InclusionSlot(state, 1)
|
||||
if err == nil {
|
||||
t.Fatal("InclusionSlot should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionDistance_Ok(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{0, 1, 2, 3, 4, 5, 6, 7}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
// Validator 1 and 7 participated.
|
||||
ParticipationBitfield: []byte{'A'},
|
||||
SlotIncluded: 9},
|
||||
},
|
||||
}
|
||||
|
||||
distance, err := InclusionDistance(state, 7)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute InclusionDistance: %v", err)
|
||||
}
|
||||
|
||||
// Inclusion distance is 9 because input validator index is 7,
|
||||
// validator 7's attested slot 0 and got included slot 9.
|
||||
if distance != 9 {
|
||||
t.Errorf("Incorrect distance. Wanted: 9, got: %d", distance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionDistance_BadBitfield(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{1}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
ParticipationBitfield: []byte{},
|
||||
SlotIncluded: 9},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := InclusionDistance(state, 1)
|
||||
if err == nil {
|
||||
t.Fatal("InclusionDistance should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionDistance_NotFound(t *testing.T) {
|
||||
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1, Committee: []uint32{1}},
|
||||
}}}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
}
|
||||
|
||||
_, err := InclusionDistance(state, 1)
|
||||
if err == nil {
|
||||
t.Fatal("InclusionDistance should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustForInclusionDistance(t *testing.T) {
|
||||
tests := []struct {
|
||||
a uint64
|
||||
b uint64
|
||||
c uint64
|
||||
}{
|
||||
{a: 10, b: 1, c: 25},
|
||||
{a: 10, b: 2, c: 15},
|
||||
{a: 10, b: 16, c: 6},
|
||||
{a: 50, b: 1, c: 125},
|
||||
{a: 50, b: 16, c: 31},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if AdjustForInclusionDistance(tt.a, tt.b) != tt.c {
|
||||
t.Errorf(
|
||||
"AdjustForInclusionDistance(%d, %d) = %d, want = %d",
|
||||
tt.a, tt.b, AdjustForInclusionDistance(tt.a, tt.b), tt.c)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
package epoch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// Attestations returns the pending attestations of slots in the epoch
|
||||
// (state.slot-EPOCH_LENGTH...state.slot-1), not attestations that got
|
||||
// included in the chain during the epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in state.latest_attestations
|
||||
// if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]
|
||||
func Attestations(state *pb.BeaconState) []*pb.PendingAttestationRecord {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var thisEpochAttestations []*pb.PendingAttestationRecord
|
||||
var earliestSlot uint64
|
||||
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
|
||||
// If the state slot is less than epochLength, then the earliestSlot would
|
||||
// result in a negative number. Therefore we should default to
|
||||
// earliestSlot = 0 in this case.
|
||||
if state.Slot > epochLength {
|
||||
earliestSlot = state.Slot - epochLength
|
||||
}
|
||||
|
||||
if earliestSlot <= attestation.GetData().GetSlot() && attestation.GetData().GetSlot() < state.Slot {
|
||||
thisEpochAttestations = append(thisEpochAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return thisEpochAttestations
|
||||
}
|
||||
|
||||
// BoundaryAttestations returns the pending attestations from
|
||||
// the epoch's boundary block.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in this_epoch_attestations if a.data.epoch_boundary_root ==
|
||||
// get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot ==
|
||||
// state.justified_slot]
|
||||
func BoundaryAttestations(
|
||||
state *pb.BeaconState,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
) ([]*pb.PendingAttestationRecord, error) {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var boundaryAttestations []*pb.PendingAttestationRecord
|
||||
|
||||
for _, attestation := range thisEpochAttestations {
|
||||
|
||||
boundaryBlockRoot, err := b.BlockRoot(state, state.Slot-epochLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestationData := attestation.GetData()
|
||||
sameRoot := bytes.Equal(attestationData.JustifiedBlockRootHash32, boundaryBlockRoot)
|
||||
sameSlotNum := attestationData.JustifiedSlot == state.JustifiedSlot
|
||||
if sameRoot && sameSlotNum {
|
||||
boundaryAttestations = append(boundaryAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return boundaryAttestations, nil
|
||||
}
|
||||
|
||||
// PrevAttestations returns the attestations of the previous epoch
|
||||
// (state.slot - 2 * EPOCH_LENGTH...state.slot - EPOCH_LENGTH).
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in state.latest_attestations
|
||||
// if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]
|
||||
func PrevAttestations(state *pb.BeaconState) []*pb.PendingAttestationRecord {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var prevEpochAttestations []*pb.PendingAttestationRecord
|
||||
var earliestSlot uint64
|
||||
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
|
||||
// If the state slot is less than 2 * epochLength, then the earliestSlot would
|
||||
// result in a negative number. Therefore we should default to
|
||||
// earliestSlot = 0 in this case.
|
||||
if state.Slot > 2*epochLength {
|
||||
earliestSlot = state.Slot - 2*epochLength
|
||||
}
|
||||
|
||||
if earliestSlot <= attestation.GetData().GetSlot() &&
|
||||
attestation.GetData().GetSlot() < state.Slot-epochLength {
|
||||
prevEpochAttestations = append(prevEpochAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return prevEpochAttestations
|
||||
}
|
||||
|
||||
// PrevJustifiedAttestations returns the justified attestations
|
||||
// of the previous 2 epochs.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in this_epoch_attestations + previous_epoch_attestations
|
||||
// if a.justified_slot == state.previous_justified_slot]
|
||||
func PrevJustifiedAttestations(
|
||||
state *pb.BeaconState,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord,
|
||||
) []*pb.PendingAttestationRecord {
|
||||
var prevJustifiedAttestations []*pb.PendingAttestationRecord
|
||||
epochAttestations := append(thisEpochAttestations, prevEpochAttestations...)
|
||||
|
||||
for _, attestation := range epochAttestations {
|
||||
if attestation.GetData().GetJustifiedSlot() == state.PreviousJustifiedSlot {
|
||||
prevJustifiedAttestations = append(prevJustifiedAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return prevJustifiedAttestations
|
||||
}
|
||||
|
||||
// PrevHeadAttestations returns the pending attestations from
|
||||
// the canonical beacon chain.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// [a for a in previous_epoch_attestations
|
||||
// if a.beacon_block_root == get_block_root(state, a.slot)]
|
||||
func PrevHeadAttestations(
|
||||
state *pb.BeaconState,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord,
|
||||
) ([]*pb.PendingAttestationRecord, error) {
|
||||
var headAttestations []*pb.PendingAttestationRecord
|
||||
|
||||
for _, attestation := range prevEpochAttestations {
|
||||
canonicalBlockRoot, err := b.BlockRoot(state, attestation.GetData().GetSlot())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestationData := attestation.GetData()
|
||||
if bytes.Equal(attestationData.BeaconBlockRootHash32, canonicalBlockRoot) {
|
||||
headAttestations = append(headAttestations, attestation)
|
||||
}
|
||||
}
|
||||
return headAttestations, nil
|
||||
}
|
@ -1,243 +0,0 @@
|
||||
package epoch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestEpochAttestations(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var pendingAttestations []*pb.PendingAttestationRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
|
||||
pendingAttestations = append(pendingAttestations, &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: i,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{LatestAttestations: pendingAttestations}
|
||||
|
||||
tests := []struct {
|
||||
stateSlot uint64
|
||||
firstAttestationSlot uint64
|
||||
}{
|
||||
{
|
||||
stateSlot: 10,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 63,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 64,
|
||||
firstAttestationSlot: 64 - params.BeaconConfig().EpochLength,
|
||||
}, {
|
||||
stateSlot: 127,
|
||||
firstAttestationSlot: 127 - params.BeaconConfig().EpochLength,
|
||||
}, {
|
||||
stateSlot: 128,
|
||||
firstAttestationSlot: 128 - params.BeaconConfig().EpochLength,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot
|
||||
|
||||
if Attestations(state)[0].GetData().GetSlot() != tt.firstAttestationSlot {
|
||||
t.Errorf(
|
||||
"Result slot was an unexpected value. Wanted %d, got %d",
|
||||
tt.firstAttestationSlot,
|
||||
Attestations(state)[0].GetData().GetSlot(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEpochBoundaryAttestations(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
epochAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{0}, JustifiedSlot: 0}},
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{1}, JustifiedSlot: 1}},
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{2}, JustifiedSlot: 2}},
|
||||
{Data: &pb.AttestationData{JustifiedBlockRootHash32: []byte{3}, JustifiedSlot: 3}},
|
||||
}
|
||||
|
||||
var latestBlockRootHash [][]byte
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength; i++ {
|
||||
latestBlockRootHash = append(latestBlockRootHash, []byte{byte(i)})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
LatestAttestations: epochAttestations,
|
||||
Slot: params.BeaconConfig().EpochLength,
|
||||
LatestBlockRootHash32S: [][]byte{},
|
||||
}
|
||||
|
||||
epochBoundaryAttestation, err := BoundaryAttestations(state, epochAttestations)
|
||||
if err == nil {
|
||||
t.Fatalf("EpochBoundaryAttestations should have failed with empty block root hash")
|
||||
}
|
||||
|
||||
state.LatestBlockRootHash32S = latestBlockRootHash
|
||||
epochBoundaryAttestation, err = BoundaryAttestations(state, epochAttestations)
|
||||
if err != nil {
|
||||
t.Fatalf("EpochBoundaryAttestations failed: %v", err)
|
||||
}
|
||||
|
||||
if epochBoundaryAttestation[0].GetData().GetJustifiedSlot() != 0 {
|
||||
t.Errorf("Wanted justified slot 0 for epoch boundary attestation, got: %d", epochBoundaryAttestation[0].GetData().GetJustifiedSlot())
|
||||
}
|
||||
|
||||
if !bytes.Equal(epochBoundaryAttestation[0].GetData().GetJustifiedBlockRootHash32(), []byte{0}) {
|
||||
t.Errorf("Wanted justified block hash [0] for epoch boundary attestation, got: %v",
|
||||
epochBoundaryAttestation[0].GetData().GetJustifiedBlockRootHash32())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevEpochAttestations(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var pendingAttestations []*pb.PendingAttestationRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*4; i++ {
|
||||
pendingAttestations = append(pendingAttestations, &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: i,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{LatestAttestations: pendingAttestations}
|
||||
|
||||
tests := []struct {
|
||||
stateSlot uint64
|
||||
firstAttestationSlot uint64
|
||||
}{
|
||||
{
|
||||
stateSlot: 10,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 127,
|
||||
firstAttestationSlot: 0,
|
||||
},
|
||||
{
|
||||
stateSlot: 383,
|
||||
firstAttestationSlot: 383 - 2*params.BeaconConfig().EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 129,
|
||||
firstAttestationSlot: 129 - 2*params.BeaconConfig().EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 256,
|
||||
firstAttestationSlot: 256 - 2*params.BeaconConfig().EpochLength,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot
|
||||
|
||||
if PrevAttestations(state)[0].GetData().GetSlot() != tt.firstAttestationSlot {
|
||||
t.Errorf(
|
||||
"Result slot was an unexpected value. Wanted %d, got %d",
|
||||
tt.firstAttestationSlot,
|
||||
Attestations(state)[0].GetData().GetSlot(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevJustifiedAttestations(t *testing.T) {
|
||||
prevEpochAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 0}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 2}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 5}},
|
||||
{Data: &pb.AttestationData{Shard: 2, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{Shard: 3, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 999}},
|
||||
}
|
||||
|
||||
thisEpochAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 0}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 10}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 15}},
|
||||
{Data: &pb.AttestationData{Shard: 0, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{Shard: 1, JustifiedSlot: 100}},
|
||||
{Data: &pb.AttestationData{JustifiedSlot: 888}},
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{PreviousJustifiedSlot: 100}
|
||||
|
||||
prevJustifiedAttestations := PrevJustifiedAttestations(state, thisEpochAttestations, prevEpochAttestations)
|
||||
|
||||
for i, attestation := range prevJustifiedAttestations {
|
||||
if attestation.GetData().Shard != uint64(i) {
|
||||
t.Errorf("Wanted shard %d, got %d", i, attestation.GetData().Shard)
|
||||
}
|
||||
if attestation.GetData().GetJustifiedSlot() != 100 {
|
||||
t.Errorf("Wanted justified slot 100, got %d", attestation.GetData().GetJustifiedSlot())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadAttestations_Ok(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
prevAttestations := []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: 1, BeaconBlockRootHash32: []byte{'A'}}},
|
||||
{Data: &pb.AttestationData{Slot: 2, BeaconBlockRootHash32: []byte{'B'}}},
|
||||
{Data: &pb.AttestationData{Slot: 3, BeaconBlockRootHash32: []byte{'C'}}},
|
||||
{Data: &pb.AttestationData{Slot: 4, BeaconBlockRootHash32: []byte{'D'}}},
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{Slot: 5, LatestBlockRootHash32S: [][]byte{{'A'}, {'X'}, {'C'}, {'Y'}}}
|
||||
|
||||
headAttestations, err := PrevHeadAttestations(state, prevAttestations)
|
||||
if err != nil {
|
||||
t.Fatalf("PrevHeadAttestations failed with %v", err)
|
||||
}
|
||||
|
||||
if headAttestations[0].GetData().GetSlot() != 1 {
|
||||
t.Errorf("headAttestations[0] wanted slot 1, got slot %d", headAttestations[0].GetData().GetSlot())
|
||||
}
|
||||
if headAttestations[1].GetData().GetSlot() != 3 {
|
||||
t.Errorf("headAttestations[1] wanted slot 3, got slot %d", headAttestations[1].GetData().GetSlot())
|
||||
}
|
||||
if !bytes.Equal([]byte{'A'}, headAttestations[0].GetData().GetBeaconBlockRootHash32()) {
|
||||
t.Errorf("headAttestations[0] wanted hash [A], got slot %v",
|
||||
headAttestations[0].GetData().GetBeaconBlockRootHash32())
|
||||
}
|
||||
if !bytes.Equal([]byte{'C'}, headAttestations[1].GetData().GetBeaconBlockRootHash32()) {
|
||||
t.Errorf("headAttestations[1] wanted hash [C], got slot %v",
|
||||
headAttestations[1].GetData().GetBeaconBlockRootHash32())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadAttestations_NotOk(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
prevAttestations := []*pb.PendingAttestationRecord{{Data: &pb.AttestationData{Slot: 1}}}
|
||||
|
||||
state := &pb.BeaconState{Slot: 0}
|
||||
|
||||
if _, err := PrevHeadAttestations(state, prevAttestations); err == nil {
|
||||
t.Fatal("PrevHeadAttestations should have failed with invalid range")
|
||||
}
|
||||
}
|
@ -268,16 +268,8 @@ func TestAttestationParticipants_ok(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
var validators []*pb.ValidatorRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().BootstrappedValidatorsCount; i++ {
|
||||
validators = append(validators, &pb.ValidatorRecord{
|
||||
Pubkey: []byte{byte(i)},
|
||||
})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
|
||||
attestationData := &pb.AttestationData{}
|
||||
|
@ -500,6 +500,39 @@ func ValidatorIndices(
|
||||
return attesterIndicesIntersection, nil
|
||||
}
|
||||
|
||||
// AttestingValidatorIndices returns the shard committee validator indices
|
||||
// if the validator shard committee matches the input attestations.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let attesting_validator_indices(shard_committee, shard_block_root)
|
||||
// be the union of the validator index sets given by
|
||||
// [get_attestation_participants(state, a.data, a.participation_bitfield)
|
||||
// for a in this_epoch_attestations + previous_epoch_attestations
|
||||
// if a.shard == shard_committee.shard and a.shard_block_root == shard_block_root]
|
||||
func AttestingValidatorIndices(
|
||||
state *pb.BeaconState,
|
||||
shardCommittee *pb.ShardAndCommittee,
|
||||
shardBlockRoot []byte,
|
||||
thisEpochAttestations []*pb.PendingAttestationRecord,
|
||||
prevEpochAttestations []*pb.PendingAttestationRecord) ([]uint32, error) {
|
||||
|
||||
var validatorIndicesCommittees []uint32
|
||||
attestations := append(thisEpochAttestations, prevEpochAttestations...)
|
||||
|
||||
for _, attestation := range attestations {
|
||||
if attestation.Data.Shard == shardCommittee.Shard &&
|
||||
bytes.Equal(attestation.Data.ShardBlockRootHash32, shardBlockRoot) {
|
||||
|
||||
validatorIndicesCommittee, err := AttestationParticipants(state, attestation.Data, attestation.ParticipationBitfield)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attester indices: %v", err)
|
||||
}
|
||||
validatorIndicesCommittees = slices.Union(validatorIndicesCommittees, validatorIndicesCommittee)
|
||||
}
|
||||
}
|
||||
return validatorIndicesCommittees, nil
|
||||
}
|
||||
|
||||
// AttestingBalance returns the combined balances from the input validator
|
||||
// records.
|
||||
//
|
||||
|
@ -794,3 +794,96 @@ func TestBeaconProposerIndex(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidatorIndices_Ok(t *testing.T) {
|
||||
if params.BeaconConfig().EpochLength != 64 {
|
||||
t.Errorf("EpochLength should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var committeeIndices []uint32
|
||||
for i := uint32(0); i < 8; i++ {
|
||||
committeeIndices = append(committeeIndices, i)
|
||||
}
|
||||
|
||||
var shardAndCommittees []*pb.ShardAndCommitteeArray
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
|
||||
shardAndCommittees = append(shardAndCommittees, &pb.ShardAndCommitteeArray{
|
||||
ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: i, Committee: committeeIndices},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
}
|
||||
|
||||
prevAttestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 3,
|
||||
Shard: 3,
|
||||
ShardBlockRootHash32: []byte{'B'},
|
||||
},
|
||||
ParticipationBitfield: []byte{'A'}, // 01000001 = 1,7
|
||||
}
|
||||
|
||||
thisAttestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 3,
|
||||
Shard: 3,
|
||||
ShardBlockRootHash32: []byte{'B'},
|
||||
},
|
||||
ParticipationBitfield: []byte{'F'}, // 01000110 = 1,5,6
|
||||
}
|
||||
|
||||
indices, err := AttestingValidatorIndices(
|
||||
state,
|
||||
shardAndCommittees[3].ArrayShardAndCommittee[0],
|
||||
[]byte{'B'},
|
||||
[]*pb.PendingAttestationRecord{thisAttestation},
|
||||
[]*pb.PendingAttestationRecord{prevAttestation})
|
||||
if err != nil {
|
||||
t.Fatalf("could not execute AttestingValidatorIndices: %v", err)
|
||||
}
|
||||
|
||||
// Union(1,7,1,5,6) = 1,5,6,7
|
||||
if !reflect.DeepEqual(indices, []uint32{1, 5, 6, 7}) {
|
||||
t.Errorf("could not get incorrect validator indices. Wanted: %v, got: %v",
|
||||
[]uint32{1, 5, 6, 7}, indices)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidatorIndices_OutOfBound(t *testing.T) {
|
||||
shardAndCommittees := []*pb.ShardAndCommitteeArray{
|
||||
{ArrayShardAndCommittee: []*pb.ShardAndCommittee{
|
||||
{Shard: 1},
|
||||
}},
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
ShardAndCommitteesAtSlots: shardAndCommittees,
|
||||
Slot: 5,
|
||||
}
|
||||
|
||||
attestation := &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: 0,
|
||||
Shard: 1,
|
||||
ShardBlockRootHash32: []byte{'B'},
|
||||
},
|
||||
ParticipationBitfield: []byte{'A'}, // 01000001 = 1,7
|
||||
}
|
||||
|
||||
_, err := AttestingValidatorIndices(
|
||||
state,
|
||||
shardAndCommittees[0].ArrayShardAndCommittee[0],
|
||||
[]byte{'B'},
|
||||
[]*pb.PendingAttestationRecord{attestation},
|
||||
nil)
|
||||
|
||||
// This will fail because participation bitfield is length:1, committee bitfield is length 0.
|
||||
if err == nil {
|
||||
t.Fatal("AttestingValidatorIndices should have failed with incorrect bitfield")
|
||||
}
|
||||
}
|
||||
|
@ -45,3 +45,15 @@ func Bytes8(x uint64) []byte {
|
||||
func FromBytes8(x []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(x)
|
||||
}
|
||||
|
||||
// LowerThan returns true if byte slice x is lower than byte slice y. (big endian format)
|
||||
// This is used in spec to compare winning block root hash.
|
||||
// Mentioned in spec as "ties broken by favoring lower `shard_block_root` values".
|
||||
func LowerThan(x []byte, y []byte) bool {
|
||||
for i, b := range x {
|
||||
if b > y[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user