mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
committed by
Yutaro Mori
parent
f0abbf6f26
commit
d30d81a608
@@ -418,7 +418,7 @@ func (b *BeaconChain) getSignedParentHashes(block *types.Block, attestation *pb.
|
||||
// getAttesterIndices returns the attester committee of based from attestation's shard ID and slot number.
|
||||
func (b *BeaconChain) getAttesterIndices(attestation *pb.AttestationRecord) ([]uint32, error) {
|
||||
lastStateRecalc := b.CrystallizedState().LastStateRecalc()
|
||||
// TODO: IndicesForHeights will return default value because the spec for dynasty transition is not finalized.
|
||||
// TODO: IndicesForSlots will return default value because the spec for dynasty transition is not finalized.
|
||||
shardCommitteeArray := b.CrystallizedState().IndicesForSlots()
|
||||
shardCommittee := shardCommitteeArray[attestation.Slot-lastStateRecalc].ArrayShardAndCommittee
|
||||
for i := 0; i < len(shardCommittee); i++ {
|
||||
|
||||
@@ -212,10 +212,10 @@ func (c *ChainService) updateHead(slot uint64) {
|
||||
canonicalCrystallizedState.CrosslinkingStartShard())
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Unable to get validators by height and by shard: %v", err)
|
||||
log.Errorf("Unable to get validators by slot and by shard: %v", err)
|
||||
return
|
||||
}
|
||||
log.Debugf("Received %d validators by height", len(vals))
|
||||
log.Debugf("Received %d validators by slot", len(vals))
|
||||
|
||||
canonicalBlock := c.processedBlocksBySlot[c.lastSlot][0]
|
||||
h, err := canonicalBlock.Hash()
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func ShuffleValidatorsToCommittees(seed common.Hash, activeValidators []*pb.ValidatorRecord, dynasty uint64, crosslinkStartShard uint64) ([]*pb.ShardAndCommitteeArray, error) {
|
||||
indices := ActiveValidatorIndices(activeValidators, dynasty)
|
||||
|
||||
// split the shuffled list for heights.
|
||||
// split the shuffled list for slot.
|
||||
shuffledValidators, err := utils.ShuffleIndices(seed, indices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
)
|
||||
|
||||
func TestGetIndicesForHeight(t *testing.T) {
|
||||
func TestGetIndicesForSlot(t *testing.T) {
|
||||
state := &pb.CrystallizedState{
|
||||
LastStateRecalc: 1,
|
||||
IndicesForSlots: []*pb.ShardAndCommitteeArray{
|
||||
@@ -23,19 +23,19 @@ func TestGetIndicesForHeight(t *testing.T) {
|
||||
{ShardId: 4, Committee: []uint32{5, 6, 7, 8, 9}},
|
||||
}},
|
||||
}}
|
||||
if _, err := GetIndicesForHeight(state.IndicesForSlots, state.LastStateRecalc, 1000); err == nil {
|
||||
t.Error("getIndicesForHeight should have failed with invalid height")
|
||||
if _, err := GetIndicesForSlot(state.IndicesForSlots, state.LastStateRecalc, 1000); err == nil {
|
||||
t.Error("getIndicesForSlot should have failed with invalid slot")
|
||||
}
|
||||
committee, err := GetIndicesForHeight(state.IndicesForSlots, state.LastStateRecalc, 1)
|
||||
committee, err := GetIndicesForSlot(state.IndicesForSlots, state.LastStateRecalc, 1)
|
||||
if err != nil {
|
||||
t.Errorf("getIndicesForHeight failed: %v", err)
|
||||
t.Errorf("getIndicesForSlot failed: %v", err)
|
||||
}
|
||||
if committee.ArrayShardAndCommittee[0].ShardId != 1 {
|
||||
t.Errorf("getIndicesForHeight returns shardID should be 1, got: %v", committee.ArrayShardAndCommittee[0].ShardId)
|
||||
t.Errorf("getIndicesForSlot returns shardID should be 1, got: %v", committee.ArrayShardAndCommittee[0].ShardId)
|
||||
}
|
||||
committee, _ = GetIndicesForHeight(state.IndicesForSlots, state.LastStateRecalc, 2)
|
||||
committee, _ = GetIndicesForSlot(state.IndicesForSlots, state.LastStateRecalc, 2)
|
||||
if committee.ArrayShardAndCommittee[0].ShardId != 3 {
|
||||
t.Errorf("getIndicesForHeight returns shardID should be 3, got: %v", committee.ArrayShardAndCommittee[0].ShardId)
|
||||
t.Errorf("getIndicesForSlot returns shardID should be 3, got: %v", committee.ArrayShardAndCommittee[0].ShardId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ func TestMaxValidators(t *testing.T) {
|
||||
t.Errorf("GetAttestersProposer should have failed")
|
||||
}
|
||||
|
||||
// ValidatorsByHeightShard should fail the same.
|
||||
// ValidatorsBySlotShard should fail the same.
|
||||
if _, err := ShuffleValidatorsToCommittees(common.Hash{'A'}, validators, 1, 0); err == nil {
|
||||
t.Errorf("ValidatorsByHeightShard should have failed")
|
||||
t.Errorf("ValidatorsBySlotShard should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func Test1000ActiveValidators(t *testing.T) {
|
||||
|
||||
indices, err := ShuffleValidatorsToCommittees(common.Hash{'A'}, validators, 1, 0)
|
||||
if err != nil {
|
||||
t.Errorf("validatorsByHeightShard failed with %v:", err)
|
||||
t.Errorf("validatorsBySlotShard failed with %v:", err)
|
||||
}
|
||||
if len(indices) != params.CycleLength {
|
||||
t.Errorf("incorret length for validator indices. Want: %d. Got: %v", params.CycleLength, len(indices))
|
||||
@@ -122,7 +122,7 @@ func TestSmallSampleValidators(t *testing.T) {
|
||||
|
||||
indices, err := ShuffleValidatorsToCommittees(common.Hash{'A'}, validators, 1, 0)
|
||||
if err != nil {
|
||||
t.Errorf("validatorsByHeightShard failed with %v:", err)
|
||||
t.Errorf("validatorsBySlotShard failed with %v:", err)
|
||||
}
|
||||
if len(indices) != params.CycleLength {
|
||||
t.Errorf("incorret length for validator indices. Want: %d. Got: %d", params.CycleLength, len(indices))
|
||||
@@ -168,7 +168,7 @@ func TestGetCommitteeParamsLargeValidatorSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorsByHeightShardRegularValidatorSet(t *testing.T) {
|
||||
func TestValidatorsBySlotShardRegularValidatorSet(t *testing.T) {
|
||||
validatorIndices := []uint32{}
|
||||
numValidators := params.CycleLength * params.MinCommiteeSize
|
||||
for i := 0; i < numValidators; i++ {
|
||||
@@ -194,7 +194,7 @@ func TestValidatorsByHeightShardRegularValidatorSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorsByHeightShardLargeValidatorSet(t *testing.T) {
|
||||
func TestValidatorsBySlotShardLargeValidatorSet(t *testing.T) {
|
||||
validatorIndices := []uint32{}
|
||||
numValidators := params.CycleLength * params.MinCommiteeSize * 2
|
||||
for i := 0; i < numValidators; i++ {
|
||||
@@ -226,7 +226,7 @@ func TestValidatorsByHeightShardLargeValidatorSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorsByHeightShardSmallValidatorSet(t *testing.T) {
|
||||
func TestValidatorsBySlotShardSmallValidatorSet(t *testing.T) {
|
||||
validatorIndices := []uint32{}
|
||||
numValidators := params.CycleLength * params.MinCommiteeSize / 2
|
||||
for i := 0; i < numValidators; i++ {
|
||||
|
||||
@@ -101,10 +101,10 @@ func GetAttestersTotalDeposit(attestations []*pb.AttestationRecord) uint64 {
|
||||
return uint64(numOfBits) * params.DefaultBalance
|
||||
}
|
||||
|
||||
// GetIndicesForHeight returns the attester set of a given height.
|
||||
func GetIndicesForHeight(shardCommittees []*pb.ShardAndCommitteeArray, lcs uint64, height uint64) (*pb.ShardAndCommitteeArray, error) {
|
||||
if !(lcs <= height && height < lcs+params.CycleLength*2) {
|
||||
return nil, fmt.Errorf("can not return attester set of given height, input height %v has to be in between %v and %v", height, lcs, lcs+params.CycleLength*2)
|
||||
// GetIndicesForSlot returns the attester set of a given slot.
|
||||
func GetIndicesForSlot(shardCommittees []*pb.ShardAndCommitteeArray, lcs uint64, slot uint64) (*pb.ShardAndCommitteeArray, error) {
|
||||
if !(lcs <= slot && slot < lcs+params.CycleLength*2) {
|
||||
return nil, fmt.Errorf("can not return attester set of given slot, input slot %v has to be in between %v and %v", slot, lcs, lcs+params.CycleLength*2)
|
||||
}
|
||||
return shardCommittees[height-lcs], nil
|
||||
return shardCommittees[slot-lcs], nil
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ const (
|
||||
MaxValidators = 4194304
|
||||
// SlotDuration in seconds.
|
||||
SlotDuration = 8
|
||||
// Cofactor is used cutoff algorithm to select height and shard cutoffs.
|
||||
// Cofactor is used cutoff algorithm to select slot and shard cutoffs.
|
||||
Cofactor = 19
|
||||
// MinCommiteeSize is the minimal number of validator needs to be in a committee.
|
||||
MinCommiteeSize = 128
|
||||
|
||||
@@ -99,7 +99,7 @@ func (s *Service) Stop() error {
|
||||
}
|
||||
|
||||
// FetchShuffledValidatorIndices retrieves the shuffled validator indices, cutoffs, and
|
||||
// assigned attestation heights at a given crystallized state hash.
|
||||
// assigned attestation slots at a given crystallized state hash.
|
||||
// This function can be called by validators to fetch a historical list of shuffled
|
||||
// validators ata point in time corresponding to a certain crystallized state.
|
||||
func (s *Service) FetchShuffledValidatorIndices(ctx context.Context, req *pb.ShuffleRequest) (*pb.ShuffleResponse, error) {
|
||||
|
||||
@@ -140,7 +140,7 @@ func TestCrystallizedState(t *testing.T) {
|
||||
}
|
||||
crystallized.ClearIndicesForSlots()
|
||||
if !reflect.DeepEqual(crystallized.IndicesForSlots(), []*pb.ShardAndCommitteeArray{}) {
|
||||
t.Errorf("mismatched indices for heights: wanted %v, received %v", []*pb.ShardAndCommitteeArray{}, crystallized.IndicesForSlots())
|
||||
t.Errorf("mismatched indices for slots: wanted %v, received %v", []*pb.ShardAndCommitteeArray{}, crystallized.IndicesForSlots())
|
||||
}
|
||||
crystallized.CrosslinkRecords()
|
||||
crystallized.UpdateJustifiedSlot(6)
|
||||
@@ -159,7 +159,7 @@ func TestBlockHashForSlot(t *testing.T) {
|
||||
}, nil)
|
||||
block := newTestBlock(t, &pb.BeaconBlock{SlotNumber: 7})
|
||||
if _, err := state.BlockHashForSlot(200, block); err == nil {
|
||||
t.Error("getBlockHash should have failed with invalid height")
|
||||
t.Error("getBlockHash should have failed with invalid slot")
|
||||
}
|
||||
hash, err := state.BlockHashForSlot(0, block)
|
||||
if err != nil {
|
||||
|
||||
@@ -65,12 +65,12 @@ func (m *ShuffleRequest) GetCrystallizedStateHash() []byte {
|
||||
}
|
||||
|
||||
type ShuffleResponse struct {
|
||||
ShuffledValidatorIndices []uint64 `protobuf:"varint,1,rep,packed,name=shuffled_validator_indices,json=shuffledValidatorIndices,proto3" json:"shuffled_validator_indices,omitempty"`
|
||||
CutoffIndices []uint64 `protobuf:"varint,2,rep,packed,name=cutoff_indices,json=cutoffIndices,proto3" json:"cutoff_indices,omitempty"`
|
||||
AssignedAttestationHeights []uint64 `protobuf:"varint,3,rep,packed,name=assigned_attestation_heights,json=assignedAttestationHeights,proto3" json:"assigned_attestation_heights,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
ShuffledValidatorIndices []uint64 `protobuf:"varint,1,rep,packed,name=shuffled_validator_indices,json=shuffledValidatorIndices,proto3" json:"shuffled_validator_indices,omitempty"`
|
||||
CutoffIndices []uint64 `protobuf:"varint,2,rep,packed,name=cutoff_indices,json=cutoffIndices,proto3" json:"cutoff_indices,omitempty"`
|
||||
AssignedAttestationSlots []uint64 `protobuf:"varint,3,rep,packed,name=assigned_attestation_slots,json=assignedAttestationSlots,proto3" json:"assigned_attestation_slots,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ShuffleResponse) Reset() { *m = ShuffleResponse{} }
|
||||
@@ -111,9 +111,9 @@ func (m *ShuffleResponse) GetCutoffIndices() []uint64 {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ShuffleResponse) GetAssignedAttestationHeights() []uint64 {
|
||||
func (m *ShuffleResponse) GetAssignedAttestationSlots() []uint64 {
|
||||
if m != nil {
|
||||
return m.AssignedAttestationHeights
|
||||
return m.AssignedAttestationSlots
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ message ShuffleRequest {
|
||||
message ShuffleResponse {
|
||||
repeated uint64 shuffled_validator_indices = 1;
|
||||
repeated uint64 cutoff_indices = 2;
|
||||
repeated uint64 assigned_attestation_heights = 3;
|
||||
repeated uint64 assigned_attestation_slots = 3;
|
||||
}
|
||||
|
||||
message ProposeRequest {
|
||||
|
||||
@@ -21,7 +21,7 @@ type Service struct {
|
||||
cancel context.CancelFunc
|
||||
rpcClient types.RPCClient
|
||||
validatorIndex int
|
||||
assignedHeight uint64
|
||||
assignedSlot uint64
|
||||
responsibility string
|
||||
attesterChan chan bool
|
||||
proposerChan chan bool
|
||||
@@ -96,13 +96,13 @@ func (s *Service) fetchBeaconBlocks(client pb.BeaconServiceClient) {
|
||||
}
|
||||
log.WithField("slotNumber", block.GetSlotNumber()).Info("Latest beacon block slot number")
|
||||
|
||||
// Based on the height determined from the latest crystallized state, check if
|
||||
// it matches the latest received beacon height.
|
||||
// Based on the slot determined from the latest crystallized state, check if
|
||||
// it matches the latest received beacon slot.
|
||||
if s.responsibility == "proposer" {
|
||||
log.WithField("slotNumber", block.GetSlotNumber()).Info("Assigned proposal slot number reached")
|
||||
s.responsibility = ""
|
||||
s.proposerChan <- true
|
||||
} else if s.responsibility == "attester" && block.GetSlotNumber() == s.assignedHeight {
|
||||
} else if s.responsibility == "attester" && block.GetSlotNumber() == s.assignedSlot {
|
||||
// TODO: Let the validator know a few slots in advance if its attestation slot is coming up
|
||||
log.Info("Assigned attestation slot number reached")
|
||||
s.responsibility = ""
|
||||
@@ -185,27 +185,27 @@ func (s *Service) fetchCrystallizedState(client pb.BeaconServiceClient) {
|
||||
// If the condition above did not pass, the validator is an attester.
|
||||
s.responsibility = "attester"
|
||||
|
||||
// Based on the cutoff and assigned heights, determine the beacon block
|
||||
// height at which attester has to perform its responsibility.
|
||||
currentAssignedHeights := res.GetAssignedAttestationHeights()
|
||||
// Based on the cutoff and assigned slots, determine the beacon block
|
||||
// slot at which attester has to perform its responsibility.
|
||||
currentAssignedSlots := res.GetAssignedAttestationSlots()
|
||||
currentCutoffs := res.GetCutoffIndices()
|
||||
|
||||
// The algorithm functions as follows:
|
||||
// Given a list of heights: [0 19 38 57 12 31 50] and
|
||||
// Given a list of slots: [0 19 38 57 12 31 50] and
|
||||
// A list of cutoff indices: [0 142 285 428 571 714 857 1000]
|
||||
// if the validator index is between 0-142, it can attest at height 0, if it is
|
||||
// between 142-285, that validator can attest at height 19, etc.
|
||||
heightIndex := 0
|
||||
// if the validator index is between 0-142, it can attest at slot 0, if it is
|
||||
// between 142-285, that validator can attest at slot 19, etc.
|
||||
slotIndex := 0
|
||||
for i := 0; i < len(currentCutoffs)-1; i++ {
|
||||
lowCutoff := currentCutoffs[i]
|
||||
highCutoff := currentCutoffs[i+1]
|
||||
if (uint64(s.validatorIndex) >= lowCutoff) && (uint64(s.validatorIndex) <= highCutoff) {
|
||||
break
|
||||
}
|
||||
heightIndex++
|
||||
slotIndex++
|
||||
}
|
||||
s.assignedHeight = currentAssignedHeights[heightIndex]
|
||||
log.Debug("Validator selected as attester at slot number: %d", s.assignedHeight)
|
||||
s.assignedSlot = currentAssignedSlots[slotIndex]
|
||||
log.Debug("Validator selected as attester at slot number: %d", s.assignedSlot)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,11 +93,11 @@ func TestFetchBeaconBlocks(t *testing.T) {
|
||||
// Create mock for the stream returned by LatestBeaconBlock.
|
||||
stream := internal.NewMockBeaconService_LatestBeaconBlockClient(ctrl)
|
||||
|
||||
// If the block's slot number from the stream matches the assigned attestation height,
|
||||
// If the block's slot number from the stream matches the assigned attestation slot,
|
||||
// trigger a log.
|
||||
stream.EXPECT().Recv().Return(&pbp2p.BeaconBlock{SlotNumber: 10}, nil)
|
||||
stream.EXPECT().Recv().Return(&pbp2p.BeaconBlock{}, io.EOF)
|
||||
b.assignedHeight = 10
|
||||
b.assignedSlot = 10
|
||||
b.responsibility = "attester"
|
||||
|
||||
mockServiceClient := internal.NewMockBeaconServiceClient(ctrl)
|
||||
@@ -243,7 +243,7 @@ func TestFetchCrystallizedState(t *testing.T) {
|
||||
|
||||
testutil.AssertLogsContain(t, hook, "Could not fetch shuffled validator indices: something went wrong")
|
||||
|
||||
// Height should be assigned based on the result of ShuffleValidators.
|
||||
// Slot should be assigned based on the result of ShuffleValidators.
|
||||
validator1 := &pbp2p.ValidatorRecord{WithdrawalAddress: []byte("0x0"), StartDynasty: 1, EndDynasty: 10}
|
||||
validator2 := &pbp2p.ValidatorRecord{WithdrawalAddress: []byte("0x1"), StartDynasty: 1, EndDynasty: 10}
|
||||
validator3 := &pbp2p.ValidatorRecord{WithdrawalAddress: []byte{}, StartDynasty: 1, EndDynasty: 10}
|
||||
@@ -260,9 +260,9 @@ func TestFetchCrystallizedState(t *testing.T) {
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(&pb.ShuffleResponse{
|
||||
AssignedAttestationHeights: []uint64{0, 1, 2},
|
||||
CutoffIndices: []uint64{0, 1, 2},
|
||||
ShuffledValidatorIndices: []uint64{2, 1, 0},
|
||||
AssignedAttestationSlots: []uint64{0, 1, 2},
|
||||
CutoffIndices: []uint64{0, 1, 2},
|
||||
ShuffledValidatorIndices: []uint64{2, 1, 0},
|
||||
}, nil)
|
||||
|
||||
b.fetchCrystallizedState(mockServiceClient)
|
||||
|
||||
Reference in New Issue
Block a user