mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Aligning ETH2.0 Spec - Implemented Slot & Epoch Helpers (#1447)
* starting to use SlotToEpoch... * updated exisiting functions... * fixed epoch tests * fixed rest of the tests * tests for newly added helper functions * fixed visiblity * added PrevEpoch and NextEpoch helpers * lint * removed file from other commit
This commit is contained in:
committed by
Nishant Das
parent
72542d5fc7
commit
cdf50e2fa2
@@ -6,6 +6,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/attestations",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
|
||||
@@ -6,6 +6,7 @@ package attestations
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -27,16 +28,15 @@ func Key(att *pb.AttestationData) [32]byte {
|
||||
// def is_double_vote(attestation_data_1: AttestationData,
|
||||
// attestation_data_2: AttestationData) -> bool
|
||||
// """
|
||||
// Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``.
|
||||
// Returns True if the provided ``AttestationData`` are slashable
|
||||
// due to a 'double vote'.
|
||||
// Checks if the two ``AttestationData`` have the same target.
|
||||
// """
|
||||
// target_epoch_1 = attestation_data_1.slot // EPOCH_LENGTH
|
||||
// target_epoch_2 = attestation_data_2.slot // EPOCH_LENGTH
|
||||
// target_epoch_1 = slot_to_epoch(attestation_data_1.slot)
|
||||
// target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||
// return target_epoch_1 == target_epoch_2
|
||||
func IsDoubleVote(attestation1 *pb.AttestationData, attestation2 *pb.AttestationData) bool {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
return attestation1.Slot/epochLength == attestation2.Slot/epochLength
|
||||
targetEpoch1 := helpers.SlotToEpoch(attestation1.Slot)
|
||||
targetEpoch2 := helpers.SlotToEpoch(attestation2.Slot)
|
||||
return targetEpoch1 == targetEpoch2
|
||||
}
|
||||
|
||||
// IsSurroundVote checks if the data provided by the attestations fulfill the conditions for
|
||||
@@ -45,29 +45,20 @@ func IsDoubleVote(attestation1 *pb.AttestationData, attestation2 *pb.Attestation
|
||||
// def is_surround_vote(attestation_data_1: AttestationData,
|
||||
// attestation_data_2: AttestationData) -> bool:
|
||||
// """
|
||||
// Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``.
|
||||
// Returns True if the provided ``AttestationData`` are slashable
|
||||
// due to a 'surround vote'.
|
||||
// Note: parameter order matters as this function only checks
|
||||
// that ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||
// Checks if ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||
// """
|
||||
// source_epoch_1 = attestation_data_1.justified_slot // EPOCH_LENGTH
|
||||
// source_epoch_2 = attestation_data_2.justified_slot // EPOCH_LENGTH
|
||||
// target_epoch_1 = attestation_data_1.slot // EPOCH_LENGTH
|
||||
// target_epoch_2 = attestation_data_2.slot // EPOCH_LENGTH
|
||||
// return (
|
||||
// (source_epoch_1 < source_epoch_2) and
|
||||
// (source_epoch_2 + 1 == target_epoch_2) and
|
||||
// (target_epoch_2 < target_epoch_1)
|
||||
// )
|
||||
// source_epoch_1 = attestation_data_1.justified_epoch
|
||||
// source_epoch_2 = attestation_data_2.justified_epoch
|
||||
// target_epoch_1 = slot_to_epoch(attestation_data_1.slot)
|
||||
// target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||
//
|
||||
// return source_epoch_1 < source_epoch_2 and target_epoch_2 < target_epoch_1
|
||||
func IsSurroundVote(attestation1 *pb.AttestationData, attestation2 *pb.AttestationData) bool {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
sourceEpoch1 := attestation1.JustifiedSlot / epochLength
|
||||
sourceEpoch2 := attestation2.JustifiedSlot / epochLength
|
||||
targetEpoch1 := attestation1.Slot / epochLength
|
||||
targetEpoch2 := attestation2.Slot / epochLength
|
||||
targetEpoch1 := helpers.SlotToEpoch(attestation1.Slot)
|
||||
targetEpoch2 := helpers.SlotToEpoch(attestation2.Slot)
|
||||
|
||||
return sourceEpoch1 < sourceEpoch2 &&
|
||||
sourceEpoch2+1 == targetEpoch2 &&
|
||||
targetEpoch2 < targetEpoch1
|
||||
return sourceEpoch1 < sourceEpoch2 && targetEpoch2 < targetEpoch1
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package balances
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
@@ -148,6 +149,9 @@ func InclusionDistance(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get inclusion distance: %v", err)
|
||||
}
|
||||
if inclusionDistance == 0 {
|
||||
return nil, errors.New("could not process inclusion distance: 0")
|
||||
}
|
||||
state.ValidatorBalances[index] +=
|
||||
baseReward(state, index, baseRewardQuotient) *
|
||||
config.MinAttestationInclusionDelay /
|
||||
|
||||
@@ -10,6 +10,7 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"math"
|
||||
|
||||
block "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
b "github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
@@ -21,23 +22,14 @@ import (
|
||||
// included in the chain during the epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// return [a for a in state.latest_attestations
|
||||
// if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]
|
||||
// return [a for a in state.latest_attestations if
|
||||
// current_epoch == slot_to_epoch(a.data.slot)
|
||||
func Attestations(state *pb.BeaconState) []*pb.PendingAttestationRecord {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var thisEpochAttestations []*pb.PendingAttestationRecord
|
||||
var earliestSlot uint64
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
|
||||
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.Data.Slot && attestation.Data.Slot < state.Slot {
|
||||
if currentEpoch == helpers.SlotToEpoch(attestation.Data.Slot) {
|
||||
thisEpochAttestations = append(thisEpochAttestations, attestation)
|
||||
}
|
||||
}
|
||||
@@ -87,31 +79,14 @@ func BoundaryAttestations(
|
||||
// (state.slot - 2 * EPOCH_LENGTH...state.slot - EPOCH_LENGTH).
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// return [a for a in state.latest_attestations
|
||||
// if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]
|
||||
// return [a for a in state.latest_attestations if
|
||||
// previous_epoch == slot_to_epoch(a.data.slot)].
|
||||
func PrevAttestations(state *pb.BeaconState) []*pb.PendingAttestationRecord {
|
||||
epochLength := params.BeaconConfig().EpochLength
|
||||
var prevEpochAttestations []*pb.PendingAttestationRecord
|
||||
var earliestSlot uint64
|
||||
var lastSlot uint64
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
|
||||
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 the state slot is less than epochLength, then the lastSlot would
|
||||
// result in a negative number. Therefore we should default to
|
||||
// lastSlot = 0 in this case.
|
||||
if state.Slot > epochLength {
|
||||
lastSlot = state.Slot - epochLength
|
||||
}
|
||||
|
||||
if earliestSlot <= attestation.Data.Slot &&
|
||||
attestation.Data.Slot < lastSlot {
|
||||
if prevEpoch == helpers.SlotToEpoch(attestation.Data.Slot) {
|
||||
prevEpochAttestations = append(prevEpochAttestations, attestation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestEpochAttestations(t *testing.T) {
|
||||
}
|
||||
|
||||
var pendingAttestations []*pb.PendingAttestationRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*3; i++ {
|
||||
pendingAttestations = append(pendingAttestations, &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: i,
|
||||
@@ -52,21 +52,21 @@ func TestEpochAttestations(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
stateSlot: 10,
|
||||
firstAttestationSlot: 0,
|
||||
firstAttestationSlot: 10 - 10%config.EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 63,
|
||||
firstAttestationSlot: 0,
|
||||
firstAttestationSlot: 63 - 63%config.EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 64,
|
||||
firstAttestationSlot: 64 - params.BeaconConfig().EpochLength,
|
||||
firstAttestationSlot: 64 - 64%config.EpochLength,
|
||||
}, {
|
||||
stateSlot: 127,
|
||||
firstAttestationSlot: 127 - params.BeaconConfig().EpochLength,
|
||||
firstAttestationSlot: 127 - 127%config.EpochLength,
|
||||
}, {
|
||||
stateSlot: 128,
|
||||
firstAttestationSlot: 128 - params.BeaconConfig().EpochLength,
|
||||
firstAttestationSlot: 128 - 128%config.EpochLength,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func TestPrevEpochAttestations(t *testing.T) {
|
||||
}
|
||||
|
||||
var pendingAttestations []*pb.PendingAttestationRecord
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*4; i++ {
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochLength*5; i++ {
|
||||
pendingAttestations = append(pendingAttestations, &pb.PendingAttestationRecord{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: i,
|
||||
@@ -147,23 +147,23 @@ func TestPrevEpochAttestations(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
stateSlot: 127,
|
||||
firstAttestationSlot: 0,
|
||||
firstAttestationSlot: 127 - config.EpochLength - 127%config.EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 128,
|
||||
firstAttestationSlot: 0,
|
||||
firstAttestationSlot: 128 - config.EpochLength - 128%config.EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 383,
|
||||
firstAttestationSlot: 383 - 2*params.BeaconConfig().EpochLength,
|
||||
firstAttestationSlot: 383 - config.EpochLength - 383%config.EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 129,
|
||||
firstAttestationSlot: 129 - 2*params.BeaconConfig().EpochLength,
|
||||
firstAttestationSlot: 129 - config.EpochLength - 129%config.EpochLength,
|
||||
},
|
||||
{
|
||||
stateSlot: 256,
|
||||
firstAttestationSlot: 256 - 2*params.BeaconConfig().EpochLength,
|
||||
firstAttestationSlot: 256 - config.EpochLength - 256%config.EpochLength,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package epoch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -297,19 +298,11 @@ func ProcessPartialValidatorRegistry(state *pb.BeaconState) *pb.BeaconState {
|
||||
// Remove any attestation in state.latest_attestations such
|
||||
// that attestation.data.slot < state.slot - EPOCH_LENGTH
|
||||
func CleanupAttestations(state *pb.BeaconState) *pb.BeaconState {
|
||||
epochLength := config.EpochLength
|
||||
var earliestSlot uint64
|
||||
|
||||
// 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
|
||||
}
|
||||
currEpoch := helpers.CurrentEpoch(state)
|
||||
|
||||
var latestAttestations []*pb.PendingAttestationRecord
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
if attestation.Data.Slot >= earliestSlot {
|
||||
if helpers.SlotToEpoch(attestation.Data.Slot) >= currEpoch {
|
||||
latestAttestations = append(latestAttestations, attestation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ func TestCleanupAttestations(t *testing.T) {
|
||||
}
|
||||
epochLength := config.EpochLength
|
||||
state := &pb.BeaconState{
|
||||
Slot: 2 * epochLength,
|
||||
Slot: epochLength,
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: 1}},
|
||||
{Data: &pb.AttestationData{Slot: epochLength - 10}},
|
||||
@@ -431,7 +431,7 @@ func TestCleanupAttestations(t *testing.T) {
|
||||
},
|
||||
}
|
||||
wanted := &pb.BeaconState{
|
||||
Slot: 2 * epochLength,
|
||||
Slot: epochLength,
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{Slot: epochLength}},
|
||||
{Data: &pb.AttestationData{Slot: epochLength + 1}},
|
||||
|
||||
19
beacon-chain/core/helpers/BUILD.bazel
Normal file
19
beacon-chain/core/helpers/BUILD.bazel
Normal file
@@ -0,0 +1,19 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["slot_epoch.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["slot_epoch_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//proto/beacon/p2p/v1:go_default_library"],
|
||||
)
|
||||
53
beacon-chain/core/helpers/slot_epoch.go
Normal file
53
beacon-chain/core/helpers/slot_epoch.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var config = params.BeaconConfig()
|
||||
|
||||
// SlotToEpoch returns the epoch number of the input slot.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def slot_to_epoch(slot: SlotNumber) -> EpochNumber:
|
||||
// return slot // EPOCH_LENGTH
|
||||
func SlotToEpoch(slot uint64) uint64 {
|
||||
return slot / config.EpochLength
|
||||
}
|
||||
|
||||
// CurrentEpoch returns the current epoch number calculated from
|
||||
// the slot number stored in beacon state.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_current_epoch(state: BeaconState) -> EpochNumber:
|
||||
// return slot_to_epoch(state.slot)
|
||||
func CurrentEpoch(state *pb.BeaconState) uint64 {
|
||||
return SlotToEpoch(state.Slot)
|
||||
}
|
||||
|
||||
// PrevEpoch returns the previous epoch number calculated from
|
||||
// the slot number stored in beacon state. It also checks for
|
||||
// underflow condition.
|
||||
func PrevEpoch(state *pb.BeaconState) uint64 {
|
||||
if SlotToEpoch(state.Slot) == 0 {
|
||||
return 0
|
||||
}
|
||||
return SlotToEpoch(state.Slot) - 1
|
||||
}
|
||||
|
||||
// NextEpoch returns the next epoch number calculated form
|
||||
// the slot number stored in beacon state.
|
||||
func NextEpoch(state *pb.BeaconState) uint64 {
|
||||
return SlotToEpoch(state.Slot) + 1
|
||||
}
|
||||
|
||||
// StartSlot returns the first slot number of the
|
||||
// current epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_epoch_start_slot(epoch: EpochNumber) -> SlotNumber:
|
||||
// return epoch * EPOCH_LENGTH
|
||||
func StartSlot(epoch uint64) uint64 {
|
||||
return epoch * config.EpochLength
|
||||
}
|
||||
99
beacon-chain/core/helpers/slot_epoch_test.go
Normal file
99
beacon-chain/core/helpers/slot_epoch_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
)
|
||||
|
||||
func TestSlotToEpoch(t *testing.T) {
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0 / config.EpochLength},
|
||||
{slot: 50, epoch: 0 / config.EpochLength},
|
||||
{slot: 64, epoch: 64 / config.EpochLength},
|
||||
{slot: 128, epoch: 128 / config.EpochLength},
|
||||
{slot: 200, epoch: 200 / config.EpochLength},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if tt.epoch != SlotToEpoch(tt.slot) {
|
||||
t.Errorf("SlotToEpoch(%d) = %d, wanted: %d", tt.slot, SlotToEpoch(tt.slot), tt.epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentEpoch(t *testing.T) {
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0 / config.EpochLength},
|
||||
{slot: 50, epoch: 0 / config.EpochLength},
|
||||
{slot: 64, epoch: 64 / config.EpochLength},
|
||||
{slot: 128, epoch: 128 / config.EpochLength},
|
||||
{slot: 200, epoch: 200 / config.EpochLength},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.slot}
|
||||
if tt.epoch != CurrentEpoch(state) {
|
||||
t.Errorf("CurrentEpoch(%d) = %d, wanted: %d", state.Slot, CurrentEpoch(state), tt.epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevEpoch(t *testing.T) {
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0 / config.EpochLength},
|
||||
{slot: 50, epoch: 0 / config.EpochLength},
|
||||
{slot: 64, epoch: 64/config.EpochLength - 1},
|
||||
{slot: 128, epoch: 128/config.EpochLength - 1},
|
||||
{slot: 200, epoch: 200/config.EpochLength - 1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.slot}
|
||||
if tt.epoch != PrevEpoch(state) {
|
||||
t.Errorf("PrevEpoch(%d) = %d, wanted: %d", state.Slot, PrevEpoch(state), tt.epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextEpoch(t *testing.T) {
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
epoch uint64
|
||||
}{
|
||||
{slot: 0, epoch: 0/config.EpochLength + 1},
|
||||
{slot: 50, epoch: 0/config.EpochLength + 1},
|
||||
{slot: 64, epoch: 64/config.EpochLength + 1},
|
||||
{slot: 128, epoch: 128/config.EpochLength + 1},
|
||||
{slot: 200, epoch: 200/config.EpochLength + 1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.slot}
|
||||
if tt.epoch != NextEpoch(state) {
|
||||
t.Errorf("NextEpoch(%d) = %d, wanted: %d", state.Slot, NextEpoch(state), tt.epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEpochStartSlot(t *testing.T) {
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
startSlot uint64
|
||||
}{
|
||||
{epoch: 0, startSlot: 0 * config.EpochLength},
|
||||
{epoch: 1, startSlot: 1 * config.EpochLength},
|
||||
{epoch: 10, startSlot: 10 * config.EpochLength},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.epoch}
|
||||
if tt.startSlot != StartSlot(tt.epoch) {
|
||||
t.Errorf("StartSlot(%d) = %d, wanted: %d", state.Slot, StartSlot(tt.epoch), tt.startSlot)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
|
||||
@@ -2,6 +2,7 @@ package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -347,7 +348,14 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProcessEpoch_PassesProcessingConditions(t *testing.T) {
|
||||
validatorRegistry := validators.InitialValidatorRegistry()
|
||||
var validatorRegistry []*pb.ValidatorRecord
|
||||
for i := uint64(0); i < 10; i++ {
|
||||
validatorRegistry = append(validatorRegistry,
|
||||
&pb.ValidatorRecord{
|
||||
ExitSlot: config.FarFutureSlot,
|
||||
Balance: config.MaxDeposit,
|
||||
})
|
||||
}
|
||||
validatorBalances := make([]uint64, len(validatorRegistry))
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = config.MaxDeposit
|
||||
@@ -362,8 +370,7 @@ func TestProcessEpoch_PassesProcessingConditions(t *testing.T) {
|
||||
JustifiedSlot: 64,
|
||||
JustifiedBlockRootHash32: []byte{0},
|
||||
},
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
SlotIncluded: i + config.EpochLength + 1,
|
||||
SlotIncluded: i + config.EpochLength + 1,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -418,7 +425,7 @@ func TestProcessEpoch_InactiveConditions(t *testing.T) {
|
||||
JustifiedSlot: 64,
|
||||
JustifiedBlockRootHash32: []byte{0},
|
||||
},
|
||||
ParticipationBitfield: []byte{0xff},
|
||||
ParticipationBitfield: []byte{},
|
||||
SlotIncluded: i + config.EpochLength + 1,
|
||||
})
|
||||
}
|
||||
@@ -522,23 +529,23 @@ func TestProcessEpoch_CantGetPrevValidatorIndices(t *testing.T) {
|
||||
}
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"input committee slot 1 out of bounds: %d <= slot < %d",
|
||||
config.EpochLength,
|
||||
config.EpochLength*3,
|
||||
"input committee epoch 0 out of bounds: %d <= epoch < %d",
|
||||
helpers.SlotToEpoch(config.EpochLength),
|
||||
helpers.SlotToEpoch(config.EpochLength*2),
|
||||
)
|
||||
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected: %s, received: %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEpoch_CantProcessPrevBoundaryAttestations(t *testing.T) {
|
||||
func TestProcessEpoch_CantProcessCurrentBoundaryAttestations(t *testing.T) {
|
||||
state := &pb.BeaconState{
|
||||
LatestAttestations: []*pb.PendingAttestationRecord{
|
||||
{Data: &pb.AttestationData{}},
|
||||
}}
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"could not get prev boundary attestations: slot %d out of bounds: %d <= slot < %d",
|
||||
"could not get current boundary attestations: slot %d out of bounds: %d <= slot < %d",
|
||||
state.LatestAttestations[0].Data.Slot, state.Slot, state.Slot,
|
||||
)
|
||||
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), want) {
|
||||
@@ -574,8 +581,7 @@ func TestProcessEpoch_CantProcessEjections(t *testing.T) {
|
||||
{Data: &pb.AttestationData{}, ParticipationBitfield: participationBitfield},
|
||||
}}
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"validator 0 could not exit until slot %d", 320)
|
||||
want := fmt.Sprintf("could not process inclusion distance: 0")
|
||||
|
||||
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected: %s, received: %v", want, err)
|
||||
|
||||
@@ -9,6 +9,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/validators",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bitutil:go_default_library",
|
||||
|
||||
@@ -7,6 +7,7 @@ package validators
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -63,6 +64,7 @@ func AttestationParticipants(
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(participationBitfield) != mathutil.CeilDiv8(len(committee)) {
|
||||
return nil, fmt.Errorf(
|
||||
"wanted participants bitfield length %d, got: %d",
|
||||
@@ -103,31 +105,36 @@ func CurrCommitteesCountPerSlot(state *pb.BeaconState) uint64 {
|
||||
// contains the shard associated with the committee and the validator indices
|
||||
// in that committee.
|
||||
// def get_crosslink_committees_at_slot(state: BeaconState,
|
||||
// slot: int) -> List[Tuple[List[int], int]]:
|
||||
// slot: SlotNumber) -> List[Tuple[List[ValidatorIndex], ShardNumber]]:
|
||||
// """
|
||||
// Returns the list of ``(committee, shard)`` tuples for the ``slot``.
|
||||
// """
|
||||
// state_epoch_slot = state.slot - (state.slot % EPOCH_LENGTH)
|
||||
// assert state_epoch_slot <= slot + EPOCH_LENGTH
|
||||
// assert slot < state_epoch_slot + EPOCH_LENGTH
|
||||
// offset = slot % EPOCH_LENGTH
|
||||
// epoch = slot_to_epoch(slot)
|
||||
// current_epoch = get_current_epoch(state)
|
||||
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch
|
||||
// next_epoch = current_epoch + 1
|
||||
//
|
||||
// if slot < state_epoch_slot:
|
||||
// committees_per_slot = get_previous_epoch_committee_count_per_slot(state)
|
||||
// shuffling = get_shuffling(
|
||||
// state.previous_epoch_randao_mix,
|
||||
// state.validator_registry,
|
||||
// state.previous_epoch_calculation_slot,
|
||||
// )
|
||||
// slot_start_shard = (state.previous_epoch_start_shard + committees_per_slot * offset) % SHARD_COUNT
|
||||
// assert previous_epoch <= epoch < next_epoch
|
||||
//
|
||||
// if epoch < current_epoch:
|
||||
// committees_per_epoch = get_previous_epoch_committee_count(state)
|
||||
// seed = state.previous_epoch_seed
|
||||
// shuffling_epoch = state.previous_calculation_epoch
|
||||
// shuffling_start_shard = state.previous_epoch_start_shard
|
||||
// else:
|
||||
// committees_per_slot = get_current_epoch_committee_count_per_slot(state)
|
||||
// shuffling = get_shuffling(
|
||||
// state.current_epoch_randao_mix,
|
||||
// state.validator_registry,
|
||||
// state.current_epoch_calculation_slot,
|
||||
// )
|
||||
// slot_start_shard = (state.current_epoch_start_shard + committees_per_slot * offset) % SHARD_COUNT
|
||||
// committees_per_epoch = get_current_epoch_committee_count(state)
|
||||
// seed = state.current_epoch_seed
|
||||
// shuffling_epoch = state.current_calculation_epoch
|
||||
// shuffling_start_shard = state.current_epoch_start_shard
|
||||
//
|
||||
// shuffling = get_shuffling(
|
||||
// seed,
|
||||
// state.validator_registry,
|
||||
// shuffling_epoch,
|
||||
// )
|
||||
// offset = slot % EPOCH_LENGTH
|
||||
// committees_per_slot = committees_per_epoch // EPOCH_LENGTH
|
||||
// slot_start_shard = (shuffling_start_shard + committees_per_slot * offset) % SHARD_COUNT
|
||||
//
|
||||
// return [
|
||||
// (
|
||||
@@ -137,33 +144,27 @@ func CurrCommitteesCountPerSlot(state *pb.BeaconState) uint64 {
|
||||
// for i in range(committees_per_slot)
|
||||
// ]
|
||||
func CrosslinkCommitteesAtSlot(state *pb.BeaconState, slot uint64) ([]*CrosslinkCommittee, error) {
|
||||
var earliestSlot uint64
|
||||
var countPerSlot uint64
|
||||
var startShard uint64
|
||||
var shuffledIndices [][]uint64
|
||||
var err error
|
||||
|
||||
epochLength := config.EpochLength
|
||||
startEpochSlot := state.Slot - (state.Slot % epochLength)
|
||||
wantedEpoch := helpers.SlotToEpoch(slot)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
nextEpoch := helpers.NextEpoch(state)
|
||||
|
||||
// If the start epoch 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 startEpochSlot > epochLength {
|
||||
earliestSlot = startEpochSlot - epochLength
|
||||
}
|
||||
|
||||
if slot < earliestSlot || slot >= startEpochSlot+epochLength {
|
||||
if wantedEpoch < prevEpoch || wantedEpoch >= nextEpoch {
|
||||
return nil, fmt.Errorf(
|
||||
"input committee slot %d out of bounds: %d <= slot < %d",
|
||||
slot,
|
||||
earliestSlot,
|
||||
startEpochSlot+epochLength,
|
||||
"input committee epoch %d out of bounds: %d <= epoch < %d",
|
||||
wantedEpoch,
|
||||
prevEpoch,
|
||||
currentEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
offSet := slot % config.EpochLength
|
||||
if slot < startEpochSlot {
|
||||
if wantedEpoch < currentEpoch {
|
||||
countPerSlot = prevCommitteesCountPerSlot(state)
|
||||
shuffledIndices, err = Shuffling(
|
||||
bytesutil.ToBytes32(state.PreviousEpochRandaoMixHash32),
|
||||
|
||||
@@ -258,8 +258,8 @@ func TestCrosslinkCommitteesAtSlot_Ok(t *testing.T) {
|
||||
|
||||
func TestCrosslinkCommitteesAtSlot_OutOfBound(t *testing.T) {
|
||||
want := fmt.Sprintf(
|
||||
"input committee slot %d out of bounds: %d <= slot < %d",
|
||||
config.EpochLength+1, 0, config.EpochLength,
|
||||
"input committee epoch %d out of bounds: %d <= epoch < %d",
|
||||
1, 0, 0,
|
||||
)
|
||||
|
||||
if _, err := CrosslinkCommitteesAtSlot(&pb.BeaconState{}, config.EpochLength+1); !strings.Contains(err.Error(), want) {
|
||||
|
||||
Reference in New Issue
Block a user