Get Epoch (&Boundary) Attestations Helper Functions (#1103)

This commit is contained in:
terence tsao 2018-12-14 12:49:03 -08:00 committed by Raul Jordan
parent 708daae04f
commit 53749c49d0
3 changed files with 197 additions and 0 deletions

View File

@ -0,0 +1,23 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["epoch_processing.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/core/types:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/params:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["epoch_processing_test.go"],
embed = [":go_default_library"],
deps = [
"//proto/beacon/p2p/v1:go_default_library",
"//shared/params:go_default_library",
],
)

View File

@ -0,0 +1,68 @@
package epoch
import (
"bytes"
"github.com/prysmaticlabs/prysm/beacon-chain/core/types"
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:
// this_epoch_attestations = [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().Slot && attestation.GetData().Slot < state.Slot {
thisEpochAttestations = append(thisEpochAttestations, attestation)
}
}
return thisEpochAttestations
}
// BoundaryAttestations returns the pending attestations from
// the epoch 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 ==
// if state.slot - EPOCH_LENGTH <= a.data.slot < state.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 := types.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
}

View File

@ -0,0 +1,106 @@
package epoch
import (
"bytes"
"testing"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params"
)
func TestEpochAttestations_ok(t *testing.T) {
if params.BeaconConfig().EpochLength != 64 {
t.Fatalf("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].Data.Slot != tt.firstAttestationSlot {
t.Errorf(
"Result slot was an unexpected value. Wanted %d, got %d",
tt.firstAttestationSlot,
Attestations(state)[0].Data.Slot,
)
}
}
}
func TestEpochBoundaryAttestations(t *testing.T) {
if params.BeaconConfig().EpochLength != 64 {
t.Fatalf("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().JustifiedSlot != 0 {
t.Errorf("Wanted justified slot 0 for epoch boundary attestation, got: %d", epochBoundaryAttestation[0].Data.JustifiedSlot)
}
if !bytes.Equal(epochBoundaryAttestation[0].GetData().JustifiedBlockRootHash32, []byte{0}) {
t.Errorf("Wanted justified block hash [0] for epoch boundary attestation, got: %v",
epochBoundaryAttestation[0].Data.JustifiedBlockRootHash32)
}
}